ng-virtual-list 20.7.0 → 20.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +24 -22
  2. package/fesm2022/ng-virtual-list.mjs +126 -45
  3. package/fesm2022/ng-virtual-list.mjs.map +1 -1
  4. package/index.d.ts +73 -22
  5. package/package.json +1 -1
  6. package/esm2020/lib/components/ng-virtual-list-item.component.mjs +0 -198
  7. package/esm2020/lib/const/index.mjs +0 -51
  8. package/esm2020/lib/enums/direction.mjs +0 -2
  9. package/esm2020/lib/enums/directions.mjs +0 -18
  10. package/esm2020/lib/enums/index.mjs +0 -5
  11. package/esm2020/lib/enums/method-for-selecting-types.mjs +0 -22
  12. package/esm2020/lib/enums/method-for-selecting.mjs +0 -2
  13. package/esm2020/lib/enums/methods-for-selecting.mjs +0 -22
  14. package/esm2020/lib/enums/snapping-method.mjs +0 -2
  15. package/esm2020/lib/enums/snapping-methods.mjs +0 -18
  16. package/esm2020/lib/models/base-virtual-list-item-component.mjs +0 -9
  17. package/esm2020/lib/models/collection.model.mjs +0 -3
  18. package/esm2020/lib/models/component.model.mjs +0 -2
  19. package/esm2020/lib/models/index.mjs +0 -2
  20. package/esm2020/lib/models/item.model.mjs +0 -2
  21. package/esm2020/lib/models/render-collection.model.mjs +0 -3
  22. package/esm2020/lib/models/render-item-config.model.mjs +0 -2
  23. package/esm2020/lib/models/render-item.model.mjs +0 -3
  24. package/esm2020/lib/models/scroll-direction.model.mjs +0 -2
  25. package/esm2020/lib/models/scroll-event.model.mjs +0 -2
  26. package/esm2020/lib/models/sticky-map.model.mjs +0 -2
  27. package/esm2020/lib/ng-virtual-list.component.mjs +0 -800
  28. package/esm2020/lib/ng-virtual-list.module.mjs +0 -20
  29. package/esm2020/lib/ng-virtual-list.service.mjs +0 -94
  30. package/esm2020/lib/types/id.mjs +0 -2
  31. package/esm2020/lib/types/index.mjs +0 -2
  32. package/esm2020/lib/types/rect.mjs +0 -2
  33. package/esm2020/lib/types/size.mjs +0 -2
  34. package/esm2020/lib/utils/browser.mjs +0 -3
  35. package/esm2020/lib/utils/buffer-interpolation.mjs +0 -27
  36. package/esm2020/lib/utils/cacheMap.mjs +0 -167
  37. package/esm2020/lib/utils/debounce.mjs +0 -31
  38. package/esm2020/lib/utils/disposableComponent.mjs +0 -29
  39. package/esm2020/lib/utils/eventEmitter.mjs +0 -106
  40. package/esm2020/lib/utils/index.mjs +0 -5
  41. package/esm2020/lib/utils/isDirection.mjs +0 -15
  42. package/esm2020/lib/utils/isMethodForSelecting.mjs +0 -18
  43. package/esm2020/lib/utils/scrollEvent.mjs +0 -42
  44. package/esm2020/lib/utils/snapping-method.mjs +0 -9
  45. package/esm2020/lib/utils/toggleClassName.mjs +0 -15
  46. package/esm2020/lib/utils/trackBox.mjs +0 -762
  47. package/esm2020/lib/utils/tracker.mjs +0 -143
  48. package/esm2020/ng-virtual-list.mjs +0 -5
  49. package/esm2020/public-api.mjs +0 -10
  50. package/esm2022/lib/components/ng-virtual-list-item.component.mjs +0 -190
  51. package/esm2022/lib/const/index.mjs +0 -51
  52. package/esm2022/lib/enums/direction.mjs +0 -2
  53. package/esm2022/lib/enums/directions.mjs +0 -18
  54. package/esm2022/lib/enums/index.mjs +0 -5
  55. package/esm2022/lib/enums/method-for-selecting-types.mjs +0 -22
  56. package/esm2022/lib/enums/method-for-selecting.mjs +0 -2
  57. package/esm2022/lib/enums/methods-for-selecting.mjs +0 -22
  58. package/esm2022/lib/enums/snapping-method.mjs +0 -2
  59. package/esm2022/lib/enums/snapping-methods.mjs +0 -18
  60. package/esm2022/lib/models/base-virtual-list-item-component.mjs +0 -9
  61. package/esm2022/lib/models/collection.model.mjs +0 -3
  62. package/esm2022/lib/models/component.model.mjs +0 -2
  63. package/esm2022/lib/models/index.mjs +0 -2
  64. package/esm2022/lib/models/item.model.mjs +0 -2
  65. package/esm2022/lib/models/render-collection.model.mjs +0 -3
  66. package/esm2022/lib/models/render-item-config.model.mjs +0 -2
  67. package/esm2022/lib/models/render-item.model.mjs +0 -3
  68. package/esm2022/lib/models/scroll-direction.model.mjs +0 -2
  69. package/esm2022/lib/models/scroll-event.model.mjs +0 -2
  70. package/esm2022/lib/models/sticky-map.model.mjs +0 -2
  71. package/esm2022/lib/ng-virtual-list.component.mjs +0 -624
  72. package/esm2022/lib/ng-virtual-list.module.mjs +0 -20
  73. package/esm2022/lib/ng-virtual-list.service.mjs +0 -89
  74. package/esm2022/lib/types/id.mjs +0 -2
  75. package/esm2022/lib/types/index.mjs +0 -2
  76. package/esm2022/lib/types/rect.mjs +0 -2
  77. package/esm2022/lib/types/size.mjs +0 -2
  78. package/esm2022/lib/utils/browser.mjs +0 -3
  79. package/esm2022/lib/utils/buffer-interpolation.mjs +0 -27
  80. package/esm2022/lib/utils/cacheMap.mjs +0 -168
  81. package/esm2022/lib/utils/debounce.mjs +0 -31
  82. package/esm2022/lib/utils/eventEmitter.mjs +0 -105
  83. package/esm2022/lib/utils/index.mjs +0 -5
  84. package/esm2022/lib/utils/isDirection.mjs +0 -15
  85. package/esm2022/lib/utils/isMethodForSelecting.mjs +0 -18
  86. package/esm2022/lib/utils/scrollEvent.mjs +0 -42
  87. package/esm2022/lib/utils/snapping-method.mjs +0 -9
  88. package/esm2022/lib/utils/toggleClassName.mjs +0 -15
  89. package/esm2022/lib/utils/trackBox.mjs +0 -768
  90. package/esm2022/lib/utils/tracker.mjs +0 -144
  91. package/esm2022/ng-virtual-list.mjs +0 -5
  92. package/esm2022/public-api.mjs +0 -11
  93. package/fesm2015/ng-virtual-list.mjs +0 -2582
  94. package/fesm2015/ng-virtual-list.mjs.map +0 -1
  95. package/fesm2020/ng-virtual-list.mjs +0 -2586
  96. package/fesm2020/ng-virtual-list.mjs.map +0 -1
  97. package/lib/components/ng-virtual-list-item.component.d.ts +0 -47
  98. package/lib/const/index.d.ts +0 -48
  99. package/lib/enums/direction.d.ts +0 -8
  100. package/lib/enums/directions.d.ts +0 -16
  101. package/lib/enums/index.d.ts +0 -8
  102. package/lib/enums/method-for-selecting-types.d.ts +0 -20
  103. package/lib/enums/method-for-selecting.d.ts +0 -8
  104. package/lib/enums/methods-for-selecting.d.ts +0 -20
  105. package/lib/enums/snapping-method.d.ts +0 -10
  106. package/lib/enums/snapping-methods.d.ts +0 -16
  107. package/lib/models/base-virtual-list-item-component.d.ts +0 -24
  108. package/lib/models/collection.model.d.ts +0 -9
  109. package/lib/models/component.model.d.ts +0 -3
  110. package/lib/models/index.d.ts +0 -7
  111. package/lib/models/item.model.d.ts +0 -14
  112. package/lib/models/render-collection.model.d.ts +0 -9
  113. package/lib/models/render-item-config.model.d.ts +0 -49
  114. package/lib/models/render-item.model.d.ts +0 -37
  115. package/lib/models/scroll-direction.model.d.ts +0 -5
  116. package/lib/models/scroll-event.model.d.ts +0 -50
  117. package/lib/models/sticky-map.model.d.ts +0 -14
  118. package/lib/ng-virtual-list.component.d.ts +0 -202
  119. package/lib/ng-virtual-list.module.d.ts +0 -9
  120. package/lib/ng-virtual-list.service.d.ts +0 -23
  121. package/lib/types/id.d.ts +0 -7
  122. package/lib/types/index.d.ts +0 -4
  123. package/lib/types/rect.d.ts +0 -17
  124. package/lib/types/size.d.ts +0 -16
  125. package/lib/utils/browser.d.ts +0 -2
  126. package/lib/utils/buffer-interpolation.d.ts +0 -5
  127. package/lib/utils/cacheMap.d.ts +0 -60
  128. package/lib/utils/debounce.d.ts +0 -16
  129. package/lib/utils/disposableComponent.d.ts +0 -15
  130. package/lib/utils/eventEmitter.d.ts +0 -40
  131. package/lib/utils/index.d.ts +0 -6
  132. package/lib/utils/isDirection.d.ts +0 -8
  133. package/lib/utils/isMethodForSelecting.d.ts +0 -8
  134. package/lib/utils/scrollEvent.d.ts +0 -39
  135. package/lib/utils/snapping-method.d.ts +0 -3
  136. package/lib/utils/toggleClassName.d.ts +0 -7
  137. package/lib/utils/trackBox.d.ts +0 -207
  138. package/lib/utils/tracker.d.ts +0 -49
  139. package/public-api.d.ts +0 -7
package/README.md CHANGED
@@ -109,7 +109,7 @@ export class AppComponent {
109
109
  Template:
110
110
  ```html
111
111
  <ng-virtual-list class="list" direction="horizontal" [items]="horizontalGroupItems" [itemRenderer]="horizontalGroupItemRenderer"
112
- [bufferSize]="50" [stickyMap]="horizontalGroupItemsStickyMap" [itemSize]="54" [snap]="true" (onItemClick)="onItemClick($event)"></ng-virtual-list>
112
+ [bufferSize]="50" [itemConfigMap]="horizontalGroupItemConfigMap" [itemSize]="54" [snap]="true" (onItemClick)="onItemClick($event)"></ng-virtual-list>
113
113
 
114
114
  <ng-template #horizontalGroupItemRenderer let-data="data">
115
115
  @if (data) {
@@ -131,7 +131,7 @@ Template:
131
131
 
132
132
  Component:
133
133
  ```ts
134
- import { NgVirtualListComponent, IVirtualListCollection, IVirtualListStickyMap, IRenderVirtualListItem } from 'ng-virtual-list';
134
+ import { NgVirtualListComponent, IVirtualListCollection, IVirtualListItemConfigMap, IRenderVirtualListItem } from 'ng-virtual-list';
135
135
 
136
136
  const GROUP_NAMES = ['A', 'B', 'C', 'D', 'E'];
137
137
 
@@ -145,12 +145,12 @@ interface ICollectionItem {
145
145
  }
146
146
 
147
147
  const HORIZONTAL_GROUP_ITEMS: IVirtualListCollection<ICollectionItem> = [],
148
- HORIZONTAL_GROUP_ITEMS_STICKY_MAP: IVirtualListStickyMap = {};
148
+ HORIZONTAL_GROUP_ITEM_CONFIG_MAP: IVirtualListItemConfigMap = {};
149
149
 
150
150
  for (let i = 0, l = 1000000; i < l; i++) {
151
151
  const id = i + 1, type = Math.random() > .895 ? 'group-header' : 'item';
152
152
  HORIZONTAL_GROUP_ITEMS.push({ id, type, name: type === 'group-header' ? getGroupName() : `${i}` });
153
- HORIZONTAL_GROUP_ITEMS_STICKY_MAP[id] = type === 'group-header' ? 1 : 0;
153
+ HORIZONTAL_GROUP_ITEM_CONFIG_MAP[id] = type === 'group-header' ? 1 : 0;
154
154
  }
155
155
 
156
156
  @Component({
@@ -161,7 +161,7 @@ for (let i = 0, l = 1000000; i < l; i++) {
161
161
  })
162
162
  export class AppComponent {
163
163
  horizontalGroupItems = HORIZONTAL_GROUP_ITEMS;
164
- horizontalGroupItemsStickyMap = HORIZONTAL_GROUP_ITEMS_STICKY_MAP;
164
+ horizontalGroupItemConfigMap = HORIZONTAL_GROUP_ITEM_CONFIG_MAP;
165
165
 
166
166
  onItemClick(item: IRenderVirtualListItem<ICollectionItem> | undefined) {
167
167
  if (item) {
@@ -219,7 +219,7 @@ export class AppComponent {
219
219
  Template:
220
220
  ```html
221
221
  <ng-virtual-list class="list simple" [items]="groupItems" [bufferSize]="50" [itemRenderer]="groupItemRenderer"
222
- [stickyMap]="groupItemsStickyMap" [itemSize]="40" [snap]="false"></ng-virtual-list>
222
+ [itemConfigMap]="groupItemConfigMap" [itemSize]="40" [snap]="false"></ng-virtual-list>
223
223
 
224
224
  <ng-template #groupItemRenderer let-data="data">
225
225
  @if (data) {
@@ -246,7 +246,7 @@ Template:
246
246
  Template (with snapping):
247
247
  ```html
248
248
  <ng-virtual-list class="list simple" [items]="groupItems" [bufferSize]="50" [itemRenderer]="groupItemRenderer"
249
- [stickyMap]="groupItemsStickyMap" [itemSize]="40" [snap]="true"></ng-virtual-list>
249
+ [itemConfigMap]="groupItemConfigMap" [itemSize]="40" [snap]="true"></ng-virtual-list>
250
250
 
251
251
  <ng-template #groupItemRenderer let-data="data">
252
252
  @if (data) {
@@ -268,10 +268,10 @@ Template (with snapping):
268
268
 
269
269
  Component:
270
270
  ```ts
271
- import { NgVirtualListComponent, IVirtualListCollection, IVirtualListStickyMap } from 'ng-virtual-list';
271
+ import { NgVirtualListComponent, IVirtualListCollection, IVirtualListItemConfigMap } from 'ng-virtual-list';
272
272
 
273
273
  const GROUP_ITEMS: IVirtualListCollection = [],
274
- GROUP_ITEMS_STICKY_MAP: IVirtualListStickyMap = {};
274
+ GROUP_ITEM_CONFIG_MAP: IVirtualListItemConfigMap = {};
275
275
 
276
276
  let groupIndex = 0;
277
277
  for (let i = 0, l = 10000000; i < l; i++) {
@@ -280,7 +280,7 @@ for (let i = 0, l = 10000000; i < l; i++) {
280
280
  groupIndex++;
281
281
  }
282
282
  GROUP_ITEMS.push({ id, type, name: type === 'group-header' ? `Group ${groupIndex}` : `Item: ${i}` });
283
- GROUP_ITEMS_STICKY_MAP[id] = type === 'group-header' ? 1 : 0;
283
+ GROUP_ITEM_CONFIG_MAP[id] = type === 'group-header' ? 1 : 0;
284
284
  }
285
285
 
286
286
  @Component({
@@ -291,7 +291,7 @@ for (let i = 0, l = 10000000; i < l; i++) {
291
291
  })
292
292
  export class AppComponent {
293
293
  groupItems = GROUP_ITEMS;
294
- groupItemsStickyMap = GROUP_ITEMS_STICKY_MAP;
294
+ groupItemConfigMap = GROUP_ITEM_CONFIG_MAP;
295
295
  }
296
296
 
297
297
  ```
@@ -365,7 +365,7 @@ Virtual list with height-adjustable elements.
365
365
  Template
366
366
  ```html
367
367
  <ng-virtual-list #dynamicList class="list" [items]="groupDynamicItems" [itemRenderer]="groupItemRenderer" [bufferSize]="10"
368
- [stickyMap]="groupDynamicItemsStickyMap" [dynamicSize]="true" [snap]="true"></ng-virtual-list>
368
+ [itemConfigMap]="groupDynamicItemConfigMap" [dynamicSize]="true" [snap]="true"></ng-virtual-list>
369
369
 
370
370
  <ng-template #groupItemRenderer let-data="data">
371
371
  @if (data) {
@@ -413,7 +413,7 @@ const generateText = () => {
413
413
  };
414
414
 
415
415
  const GROUP_DYNAMIC_ITEMS: IVirtualListCollection = [],
416
- GROUP_DYNAMIC_ITEMS_STICKY_MAP: IVirtualListStickyMap = {};
416
+ GROUP_DYNAMIC_ITEM_CONFIG_MAP: IVirtualListItemConfigMap = {};
417
417
 
418
418
  let groupDynamicIndex = 0;
419
419
  for (let i = 0, l = 100000; i < l; i++) {
@@ -422,7 +422,7 @@ for (let i = 0, l = 100000; i < l; i++) {
422
422
  groupDynamicIndex++;
423
423
  }
424
424
  GROUP_DYNAMIC_ITEMS.push({ id, type, name: type === 'group-header' ? `Group ${groupDynamicIndex}` : `${id}. ${generateText()}` });
425
- GROUP_DYNAMIC_ITEMS_STICKY_MAP[id] = type === 'group-header' ? 1 : 0;
425
+ GROUP_DYNAMIC_ITEM_CONFIG_MAP[id] = type === 'group-header' ? 1 : 0;
426
426
  }
427
427
 
428
428
  @Component({
@@ -433,7 +433,7 @@ for (let i = 0, l = 100000; i < l; i++) {
433
433
  })
434
434
  export class AppComponent {
435
435
  groupDynamicItems = GROUP_DYNAMIC_ITEMS;
436
- groupDynamicItemsStickyMap = GROUP_DYNAMIC_ITEMS_STICKY_MAP;
436
+ groupDynamicItemConfigMap = GROUP_DYNAMIC_ITEM_CONFIG_MAP;
437
437
  }
438
438
  ```
439
439
 
@@ -535,7 +535,9 @@ Inputs
535
535
  | bufferSize | number? = 2 | Number of elements outside the scope of visibility. Default value is 2. |
536
536
  | maxBufferSize | number? = 100 | Maximum number of elements outside the scope of visibility. Default value is 100. If maxBufferSize is set to be greater than bufferSize, then adaptive buffer mode is enabled. The greater the scroll size, the more elements are allocated for rendering. |
537
537
  | itemRenderer | TemplateRef | Rendering element template. |
538
- | stickyMap | [IVirtualListStickyMap?](https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/models/sticky-map.model.ts) | Dictionary zIndex by id of the list element. If the value is not set or equal to 0, then a simple element is displayed, if the value is greater than 0, then the sticky position mode is enabled for the element. 1 - position start, 2 - position end. |
538
+ | methodForSelecting | [MethodForSelecting](https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/enums/method-for-selecting.ts) | Method for selecting list items. Default value is 'none'. 'select' - List items are selected one by one. 'multi-select' - Multiple selection of list items. 'none' - List items are not selectable. |
539
+ | itemConfigMap | [IVirtualListItemConfigMap?](https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/models/item-config-map.model.ts) | Sets sticky position and selectable for the list item element. If sticky position is greater than 0, then sticky position is applied. If the sticky value is greater than `0`, then the sticky position mode is enabled for the element. `1` - position start, `2` - position end. Default value is `0`. Selectable determines whether an element can be selected or not. Default value is `true`. |
540
+ | selectByClick | boolean? = true | If `false`, the element is selected using the config.select method passed to the template; if `true`, the element is selected by clicking on it. The default value is `true`. |
539
541
  | snap | boolean? = false | Determines whether elements will snap. Default value is "false". |
540
542
  | snappingMethod | [SnappingMethod? = 'normal'](https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/enums/snapping-method.ts) | Snapping method. 'normal' - Normal group rendering. 'advanced' - The group is rendered on a transparent background. List items below the group are not rendered. |
541
543
  | direction | [Direction? = 'vertical'](https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/enums/direction.ts) | Determines the direction in which elements are placed. Default value is "vertical". |
@@ -573,12 +575,12 @@ Methods
573
575
 
574
576
  | Angular version | ng-virtual-list version | git | npm |
575
577
  |--|--|--|--|
576
- | 19.x | 19.7.0 | [19.x](https://github.com/DjonnyX/ng-virtual-list/tree/19.x) | [19.7.0](https://www.npmjs.com/package/ng-virtual-list/v/19.7.0) |
577
- | 18.x | 18.7.0 | [18.x](https://github.com/DjonnyX/ng-virtual-list/tree/18.x) | [18.7.0](https://www.npmjs.com/package/ng-virtual-list/v/18.7.0) |
578
- | 17.x | 17.7.0 | [17.x](https://github.com/DjonnyX/ng-virtual-list/tree/17.x) | [17.7.0](https://www.npmjs.com/package/ng-virtual-list/v/17.7.0) |
579
- | 16.x | 16.7.0 | [16.x](https://github.com/DjonnyX/ng-virtual-list/tree/16.x) | [16.7.0](https://www.npmjs.com/package/ng-virtual-list/v/16.7.0) |
580
- | 15.x | 15.7.0 | [15.x](https://github.com/DjonnyX/ng-virtual-list/tree/15.x) | [15.7.0](https://www.npmjs.com/package/ng-virtual-list/v/15.7.0) |
581
- | 14.x | 14.7.0 | [14.x](https://github.com/DjonnyX/ng-virtual-list/tree/14.x) | [14.7.0](https://www.npmjs.com/package/ng-virtual-list/v/14.7.0) |
578
+ | 19.x | 19.7.3 | [19.x](https://github.com/DjonnyX/ng-virtual-list/tree/19.x) | [19.7.3](https://www.npmjs.com/package/ng-virtual-list/v/19.7.3) |
579
+ | 18.x | 18.7.2 | [18.x](https://github.com/DjonnyX/ng-virtual-list/tree/18.x) | [18.7.2](https://www.npmjs.com/package/ng-virtual-list/v/18.7.2) |
580
+ | 17.x | 17.7.2 | [17.x](https://github.com/DjonnyX/ng-virtual-list/tree/17.x) | [17.7.2](https://www.npmjs.com/package/ng-virtual-list/v/17.7.2) |
581
+ | 16.x | 16.7.2 | [16.x](https://github.com/DjonnyX/ng-virtual-list/tree/16.x) | [16.7.2](https://www.npmjs.com/package/ng-virtual-list/v/16.7.2) |
582
+ | 15.x | 15.7.2 | [15.x](https://github.com/DjonnyX/ng-virtual-list/tree/15.x) | [15.7.2](https://www.npmjs.com/package/ng-virtual-list/v/15.7.2) |
583
+ | 14.x | 14.7.2 | [14.x](https://github.com/DjonnyX/ng-virtual-list/tree/14.x) | [14.7.2](https://www.npmjs.com/package/ng-virtual-list/v/14.7.2) |
582
584
 
583
585
  <br/>
584
586
 
@@ -69,6 +69,7 @@ const DEFAULT_BUFFER_SIZE = 2;
69
69
  const DEFAULT_MAX_BUFFER_SIZE = 100;
70
70
  const DEFAULT_LIST_SIZE = 400;
71
71
  const DEFAULT_SNAP = false;
72
+ const DEFAULT_SELECT_BY_CLICK = true;
72
73
  const DEFAULT_ENABLED_BUFFER_OPTIMIZATION = false;
73
74
  const DEFAULT_DYNAMIC_SIZE = false;
74
75
  const TRACK_BY_PROPERTY_NAME = 'id';
@@ -155,6 +156,7 @@ class NgVirtualListService {
155
156
  set methodOfSelecting(v) {
156
157
  this._$methodOfSelecting.next(v);
157
158
  }
159
+ selectByClick = DEFAULT_SELECT_BY_CLICK;
158
160
  _trackBox;
159
161
  constructor() {
160
162
  this._$methodOfSelecting.pipe(takeUntilDestroyed(), tap(v => {
@@ -181,25 +183,61 @@ class NgVirtualListService {
181
183
  })).subscribe();
182
184
  }
183
185
  setSelectedIds(ids) {
184
- this._$selectedIds.next(ids);
186
+ if (JSON.stringify(this._$selectedIds.getValue()) !== JSON.stringify(ids)) {
187
+ this._$selectedIds.next(ids);
188
+ }
185
189
  }
186
190
  itemClick(data) {
187
191
  this._$itemClick.next(data);
188
- if (data) {
192
+ if (this.selectByClick) {
193
+ this.select(data);
194
+ }
195
+ }
196
+ /**
197
+ * Selects a list item
198
+ * @param data
199
+ * @param selected - If the value is undefined, then the toggle method is executed, if false or true, then the selection/deselection is performed.
200
+ */
201
+ select(data, selected = undefined) {
202
+ if (data && data.config.selectable) {
189
203
  switch (this._$methodOfSelecting.getValue()) {
190
204
  case MethodsForSelectingTypes.SELECT: {
191
205
  const curr = this._$selectedIds.getValue();
192
- this._$selectedIds.next(curr !== data?.id ? data?.id : undefined);
206
+ if (selected === undefined) {
207
+ this._$selectedIds.next(curr !== data?.id ? data?.id : undefined);
208
+ }
209
+ else {
210
+ this._$selectedIds.next(selected ? data?.id : undefined);
211
+ }
193
212
  break;
194
213
  }
195
214
  case MethodsForSelectingTypes.MULTI_SELECT: {
196
215
  const curr = [...(this._$selectedIds.getValue() || [])], index = curr.indexOf(data.id);
197
- if (index > -1) {
198
- curr.splice(index, 1);
199
- this._$selectedIds.next(curr);
216
+ if (selected === undefined) {
217
+ if (index > -1) {
218
+ curr.splice(index, 1);
219
+ this._$selectedIds.next(curr);
220
+ }
221
+ else {
222
+ this._$selectedIds.next([...curr, data.id]);
223
+ }
224
+ }
225
+ else if (selected) {
226
+ if (index > -1) {
227
+ this._$selectedIds.next(curr);
228
+ }
229
+ else {
230
+ this._$selectedIds.next([...curr, data.id]);
231
+ }
200
232
  }
201
233
  else {
202
- this._$selectedIds.next([...curr, data.id]);
234
+ if (index > -1) {
235
+ curr.splice(index, 1);
236
+ this._$selectedIds.next(curr);
237
+ }
238
+ else {
239
+ this._$selectedIds.next(curr);
240
+ }
203
241
  }
204
242
  break;
205
243
  }
@@ -242,6 +280,7 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
242
280
  _service = inject(NgVirtualListService);
243
281
  _isSelected = false;
244
282
  config = signal({});
283
+ measures = signal(undefined);
245
284
  _part = PART_DEFAULT_ITEM;
246
285
  get part() { return this._part; }
247
286
  regular = false;
@@ -254,6 +293,7 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
254
293
  this._data = v;
255
294
  this.updatePartStr(v, this._isSelected);
256
295
  this.updateConfig(v);
296
+ this.updateMeasures(v);
257
297
  this.update();
258
298
  this.data.set(v);
259
299
  }
@@ -279,6 +319,14 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
279
319
  get element() {
280
320
  return this._elementRef.nativeElement;
281
321
  }
322
+ _selectHandler = (data) =>
323
+ /**
324
+ * Selects a list item
325
+ * @param selected - If the value is undefined, then the toggle method is executed, if false or true, then the selection/deselection is performed.
326
+ */
327
+ (selected = undefined) => {
328
+ this._service.select(data, selected);
329
+ };
282
330
  constructor() {
283
331
  super();
284
332
  this._id = this._service.generateComponentId();
@@ -306,10 +354,14 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
306
354
  }
307
355
  this.updatePartStr(this._data, this._isSelected);
308
356
  this.updateConfig(this._data);
357
+ this.updateMeasures(this._data);
309
358
  })).subscribe();
310
359
  }
360
+ updateMeasures(v) {
361
+ this.measures.set(v?.measures ? { ...v.measures } : undefined);
362
+ }
311
363
  updateConfig(v) {
312
- this.config.set({ ...v?.config || {}, selected: this._isSelected });
364
+ this.config.set({ ...v?.config || {}, selected: this._isSelected, select: this._selectHandler(v) });
313
365
  }
314
366
  update() {
315
367
  const data = this._data, regular = this.regular, length = this._regularLength;
@@ -393,14 +445,14 @@ class NgVirtualListItemComponent extends BaseVirtualListItemComponent {
393
445
  this._service.itemClick(this._data);
394
446
  }
395
447
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: NgVirtualListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
396
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: NgVirtualListItemComponent, isStandalone: true, selector: "ng-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@let item = data();\r\n@let conf = config();\r\n@let renderer = itemRenderer();\r\n\r\n@if (item) {\r\n <div #listItem [part]=\"part\" class=\"ngvl-item__container\"\r\n [ngClass]=\"{'snapped': item.config.snapped, 'snapped-out': item.config.snappedOut}\" (click)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, config: conf}\" />\r\n }\r\n </div>\r\n}", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden}.ngvl-item__container{margin:0;padding:0;overflow:hidden;background-color:#fff;width:inherit;height:inherit}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
448
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: NgVirtualListItemComponent, isStandalone: true, selector: "ng-virtual-list-item", host: { attributes: { "role": "listitem" }, classAttribute: "ngvl__item" }, usesInheritance: true, ngImport: i0, template: "@let item = data();\r\n@let _config = config();\r\n@let _measures = measures();\r\n@let renderer = itemRenderer();\r\n\r\n@if (item) {\r\n <div #listItem [part]=\"part\" class=\"ngvl-item__container\"\r\n [ngClass]=\"{'snapped': item.config.snapped, 'snapped-out': item.config.snappedOut}\" (click)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data, measures: _measures, config: _config}\" />\r\n }\r\n </div>\r\n}", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden}.ngvl-item__container{margin:0;padding:0;overflow:hidden;background-color:#fff;width:inherit;height:inherit}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
397
449
  }
398
450
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: NgVirtualListItemComponent, decorators: [{
399
451
  type: Component,
400
452
  args: [{ selector: 'ng-virtual-list-item', imports: [CommonModule], host: {
401
453
  'class': 'ngvl__item',
402
454
  'role': 'listitem',
403
- }, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let item = data();\r\n@let conf = config();\r\n@let renderer = itemRenderer();\r\n\r\n@if (item) {\r\n <div #listItem [part]=\"part\" class=\"ngvl-item__container\"\r\n [ngClass]=\"{'snapped': item.config.snapped, 'snapped-out': item.config.snappedOut}\" (click)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data || {}, config: conf}\" />\r\n }\r\n </div>\r\n}", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden}.ngvl-item__container{margin:0;padding:0;overflow:hidden;background-color:#fff;width:inherit;height:inherit}\n"] }]
455
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let item = data();\r\n@let _config = config();\r\n@let _measures = measures();\r\n@let renderer = itemRenderer();\r\n\r\n@if (item) {\r\n <div #listItem [part]=\"part\" class=\"ngvl-item__container\"\r\n [ngClass]=\"{'snapped': item.config.snapped, 'snapped-out': item.config.snappedOut}\" (click)=\"onClickHandler()\">\r\n @if (renderer) {\r\n <ng-container [ngTemplateOutlet]=\"renderer\"\r\n [ngTemplateOutletContext]=\"{data: item.data, measures: _measures, config: _config}\" />\r\n }\r\n </div>\r\n}", styles: [":host{display:block;position:absolute;left:0;top:0;box-sizing:border-box;overflow:hidden}.ngvl-item__container{margin:0;padding:0;overflow:hidden;background-color:#fff;width:inherit;height:inherit}\n"] }]
404
456
  }], ctorParameters: () => [] });
405
457
 
406
458
  /**
@@ -1116,8 +1168,8 @@ class TrackBox extends CacheMap {
1116
1168
  /**
1117
1169
  * Finds the position of a collection element by the given Id
1118
1170
  */
1119
- getItemPosition(id, stickyMap, options) {
1120
- const opt = { fromItemId: id, stickyMap, ...options };
1171
+ getItemPosition(id, itemConfigMap, options) {
1172
+ const opt = { fromItemId: id, itemConfigMap, ...options };
1121
1173
  this._defaultBufferSize = opt.bufferSize;
1122
1174
  this._maxBufferSize = opt.maxBufferSize;
1123
1175
  const { scrollSize, isFromItemIdFound } = this.recalculateMetrics({
@@ -1132,8 +1184,8 @@ class TrackBox extends CacheMap {
1132
1184
  /**
1133
1185
  * Updates the collection of display objects
1134
1186
  */
1135
- updateCollection(items, stickyMap, options) {
1136
- const opt = { stickyMap, ...options }, crudDetected = this._crudDetected, deletedItemsMap = this._deletedItemsMap;
1187
+ updateCollection(items, itemConfigMap, options) {
1188
+ const opt = { itemConfigMap, ...options }, crudDetected = this._crudDetected, deletedItemsMap = this._deletedItemsMap;
1137
1189
  if (opt.dynamicSize) {
1138
1190
  this.cacheElements();
1139
1191
  }
@@ -1154,7 +1206,7 @@ class TrackBox extends CacheMap {
1154
1206
  if (opt.dynamicSize) {
1155
1207
  this.snapshot();
1156
1208
  }
1157
- const displayItems = this.generateDisplayCollection(items, stickyMap, { ...metrics, });
1209
+ const displayItems = this.generateDisplayCollection(items, itemConfigMap, { ...metrics, });
1158
1210
  return { displayItems, totalSize: metrics.totalSize, delta: metrics.delta, crudDetected };
1159
1211
  }
1160
1212
  /**
@@ -1235,7 +1287,7 @@ class TrackBox extends CacheMap {
1235
1287
  * Calculates list metrics
1236
1288
  */
1237
1289
  recalculateMetrics(options) {
1238
- const { fromItemId, bounds, collection, dynamicSize, isVertical, itemSize, bufferSize: minBufferSize, scrollSize, snap, stickyMap, enabledBufferOptimization, previousTotalSize, crudDetected, deletedItemsMap } = options;
1290
+ const { fromItemId, bounds, collection, dynamicSize, isVertical, itemSize, bufferSize: minBufferSize, scrollSize, snap, itemConfigMap, enabledBufferOptimization, previousTotalSize, crudDetected, deletedItemsMap } = options;
1239
1291
  const bufferSize = Math.max(minBufferSize, this._bufferSize), { width, height } = bounds, sizeProperty = isVertical ? HEIGHT_PROP_NAME : WIDTH_PROP_NAME, size = isVertical ? height : width, totalLength = collection.length, typicalItemSize = itemSize, w = isVertical ? width : typicalItemSize, h = isVertical ? typicalItemSize : height, map = this._map, snapshot = this._snapshot, checkOverscrollItemsLimit = Math.ceil(size / typicalItemSize), snippedPos = Math.floor(scrollSize), leftItemsWeights = [], isFromId = fromItemId !== undefined && (typeof fromItemId === 'number' && fromItemId > -1)
1240
1292
  || (typeof fromItemId === 'string' && fromItemId > '-1');
1241
1293
  let leftItemsOffset = 0, rightItemsOffset = 0;
@@ -1295,21 +1347,21 @@ class TrackBox extends CacheMap {
1295
1347
  totalSize += componentSize;
1296
1348
  if (isFromId) {
1297
1349
  if (itemById === undefined) {
1298
- if (id !== fromItemId && stickyMap && stickyMap[id] === 1) {
1350
+ if (id !== fromItemId && itemConfigMap && itemConfigMap[id]?.sticky === 1) {
1299
1351
  stickyComponentSize = componentSize;
1300
1352
  stickyCollectionItem = collectionItem;
1301
1353
  }
1302
1354
  if (id === fromItemId) {
1303
1355
  isFromItemIdFound = true;
1304
1356
  targetDisplayItemIndex = i;
1305
- if (stickyCollectionItem && stickyMap) {
1357
+ if (stickyCollectionItem && itemConfigMap) {
1306
1358
  const { num } = this.getElementNumToEnd(i, collection, map, typicalItemSize, size, isVertical);
1307
1359
  if (num > 0) {
1308
1360
  isTargetInOverscroll = true;
1309
1361
  y -= size - componentSize;
1310
1362
  }
1311
1363
  else {
1312
- if (stickyMap && !stickyMap[collectionItem.id] && y >= scrollSize && y < scrollSize + stickyComponentSize) {
1364
+ if (itemConfigMap && !itemConfigMap[collectionItem.id] && y >= scrollSize && y < scrollSize + stickyComponentSize) {
1313
1365
  const snappedY = scrollSize - stickyComponentSize;
1314
1366
  leftHiddenItemsWeight -= (snappedY - y);
1315
1367
  y = snappedY;
@@ -1492,7 +1544,7 @@ class TrackBox extends CacheMap {
1492
1544
  changes() {
1493
1545
  this.bumpVersion();
1494
1546
  }
1495
- generateDisplayCollection(items, stickyMap, metrics) {
1547
+ generateDisplayCollection(items, itemConfigMap, metrics) {
1496
1548
  const { width, height, normalizedItemWidth, normalizedItemHeight, dynamicSize, itemsOnDisplayLength, itemsFromStartToScrollEnd, isVertical, renderItems: renderItemsLength, scrollSize, sizeProperty, snap, snippedPos, startPosition, totalLength, startIndex, typicalItemSize, } = metrics, displayItems = [];
1497
1549
  if (items.length) {
1498
1550
  const actualSnippedPosition = snippedPos, isSnappingMethodAdvanced = this.isSnappingMethodAdvanced, boundsSize = isVertical ? height : width, actualEndSnippedPosition = boundsSize;
@@ -1502,7 +1554,7 @@ class TrackBox extends CacheMap {
1502
1554
  if (!items[i]) {
1503
1555
  continue;
1504
1556
  }
1505
- const id = items[i].id, sticky = stickyMap[id], size = dynamicSize ? this.get(id)?.[sizeProperty] || typicalItemSize : typicalItemSize;
1557
+ const id = items[i].id, sticky = itemConfigMap[id]?.sticky ?? 0, selectable = itemConfigMap[id]?.selectable ?? true, size = dynamicSize ? this.get(id)?.[sizeProperty] || typicalItemSize : typicalItemSize;
1506
1558
  if (sticky === 1) {
1507
1559
  const isOdd = i % 2 != 0, measures = {
1508
1560
  x: isVertical ? 0 : actualSnippedPosition,
@@ -1514,6 +1566,7 @@ class TrackBox extends CacheMap {
1514
1566
  odd: isOdd,
1515
1567
  even: !isOdd,
1516
1568
  isVertical,
1569
+ selectable,
1517
1570
  sticky,
1518
1571
  snap,
1519
1572
  snapped: true,
@@ -1537,7 +1590,7 @@ class TrackBox extends CacheMap {
1537
1590
  if (!items[i]) {
1538
1591
  continue;
1539
1592
  }
1540
- const id = items[i].id, sticky = stickyMap[id], size = dynamicSize
1593
+ const id = items[i].id, sticky = itemConfigMap[id]?.sticky ?? 0, selectable = itemConfigMap[id]?.selectable ?? true, size = dynamicSize
1541
1594
  ? this.get(id)?.[sizeProperty] || typicalItemSize
1542
1595
  : typicalItemSize;
1543
1596
  if (sticky === 2) {
@@ -1551,6 +1604,7 @@ class TrackBox extends CacheMap {
1551
1604
  odd: isOdd,
1552
1605
  even: !isOdd,
1553
1606
  isVertical,
1607
+ selectable,
1554
1608
  sticky,
1555
1609
  snap,
1556
1610
  snapped: true,
@@ -1578,9 +1632,9 @@ class TrackBox extends CacheMap {
1578
1632
  }
1579
1633
  const id = items[i].id, size = dynamicSize ? this.get(id)?.[sizeProperty] || typicalItemSize : typicalItemSize;
1580
1634
  if (id !== stickyItem?.id && id !== endStickyItem?.id) {
1581
- const isOdd = i % 2 != 0, snapped = snap && (stickyMap[id] === 1 && pos <= scrollSize || stickyMap[id] === 2 && pos >= scrollSize + boundsSize - size), measures = {
1582
- x: isVertical ? stickyMap[id] === 1 ? 0 : boundsSize - size : pos,
1583
- y: isVertical ? pos : stickyMap[id] === 2 ? boundsSize - size : 0,
1635
+ const isOdd = i % 2 != 0, sticky = itemConfigMap[id]?.sticky ?? 0, selectable = itemConfigMap[id]?.selectable ?? true, snapped = snap && (sticky === 1 && pos <= scrollSize || sticky === 2 && pos >= scrollSize + boundsSize - size), measures = {
1636
+ x: isVertical ? sticky === 1 ? 0 : boundsSize - size : pos,
1637
+ y: isVertical ? pos : sticky === 2 ? boundsSize - size : 0,
1584
1638
  width: isVertical ? normalizedItemWidth : size,
1585
1639
  height: isVertical ? size : normalizedItemHeight,
1586
1640
  delta: 0,
@@ -1588,7 +1642,8 @@ class TrackBox extends CacheMap {
1588
1642
  odd: isOdd,
1589
1643
  even: !isOdd,
1590
1644
  isVertical,
1591
- sticky: stickyMap[id],
1645
+ selectable,
1646
+ sticky: sticky,
1592
1647
  snap,
1593
1648
  snapped: false,
1594
1649
  snappedOut: false,
@@ -1601,7 +1656,7 @@ class TrackBox extends CacheMap {
1601
1656
  }
1602
1657
  const itemData = items[i];
1603
1658
  const item = { index: i, id, measures, data: itemData, config };
1604
- if (!nextSticky && stickyItemIndex < i && stickyMap[id] === 1 && (pos <= scrollSize + size + stickyItemSize)) {
1659
+ if (!nextSticky && stickyItemIndex < i && sticky === 1 && (pos <= scrollSize + size + stickyItemSize)) {
1605
1660
  item.measures.x = isVertical ? 0 : snapped ? actualSnippedPosition : pos;
1606
1661
  item.measures.y = isVertical ? snapped ? actualSnippedPosition : pos : 0;
1607
1662
  nextSticky = item;
@@ -1609,7 +1664,7 @@ class TrackBox extends CacheMap {
1609
1664
  nextSticky.measures.delta = isVertical ? (item.measures.y - scrollSize) : (item.measures.x - scrollSize);
1610
1665
  nextSticky.config.zIndex = '3';
1611
1666
  }
1612
- else if (!nextEndSticky && endStickyItemIndex > i && stickyMap[id] === 2 && (pos >= scrollSize + boundsSize - size - endStickyItemSize)) {
1667
+ else if (!nextEndSticky && endStickyItemIndex > i && sticky === 2 && (pos >= scrollSize + boundsSize - size - endStickyItemSize)) {
1613
1668
  item.measures.x = isVertical ? 0 : snapped ? actualEndSnippedPosition - size : pos;
1614
1669
  item.measures.y = isVertical ? snapped ? actualEndSnippedPosition - size : pos : 0;
1615
1670
  nextEndSticky = item;
@@ -1796,6 +1851,11 @@ class NgVirtualListComponent {
1796
1851
  * Sets the selected items.
1797
1852
  */
1798
1853
  selectedIds = input(undefined);
1854
+ /**
1855
+ * If false, the element is selected using the config.select method passed to the template;
1856
+ * if true, the element is selected by clicking on it. The default value is true.
1857
+ */
1858
+ selectByClick = input(DEFAULT_SELECT_BY_CLICK);
1799
1859
  /**
1800
1860
  * Determines whether elements will snap. Default value is "true".
1801
1861
  */
@@ -1813,10 +1873,19 @@ class NgVirtualListComponent {
1813
1873
  itemRenderer = input.required();
1814
1874
  _itemRenderer = signal(undefined);
1815
1875
  /**
1816
- * Dictionary zIndex by id of the list element. If the value is not set or equal to 0,
1817
- * then a simple element is displayed, if the value is greater than 0, then the sticky position mode is enabled for the element.
1876
+ * @deprecated
1877
+ * Use `itemConfigMap` instead.
1878
+ */
1879
+ stickyMap = input();
1880
+ /**
1881
+ * Sets sticky position and selectable for the list item element. If sticky position is greater than 0, then sticky position is applied.
1882
+ * If the sticky value is greater than `0`, then the sticky position mode is enabled for the element. `1` - position start, `2` - position end. Default value is `0`.
1883
+ * selectable determines whether an element can be selected or not. Default value is `true`.
1884
+ * @link https://github.com/DjonnyX/ng-virtual-list/blob/20.x/projects/ng-virtual-list/src/lib/models/item-config-map.model.ts
1885
+ * @author Evgenii Grebennikov
1886
+ * @email djonnyx@gmail.com
1818
1887
  */
1819
- stickyMap = input({});
1888
+ itemConfigMap = input({});
1820
1889
  _itemSizeOptions = {
1821
1890
  transform: (v) => {
1822
1891
  if (v === undefined) {
@@ -1876,7 +1945,7 @@ class NgVirtualListComponent {
1876
1945
  */
1877
1946
  snappingMethod = input(DEFAULT_SNAPPING_METHOD);
1878
1947
  /**
1879
- * Method for selecting list items.
1948
+ * Method for selecting list items. Default value is 'none'.
1880
1949
  * 'select' - List items are selected one by one.
1881
1950
  * 'multi-select' - Multiple selection of list items.
1882
1951
  * 'none' - List items are not selectable.
@@ -1985,11 +2054,14 @@ class NgVirtualListComponent {
1985
2054
  this._initialized = signal(false);
1986
2055
  this.$initialized = toObservable(this._initialized);
1987
2056
  this._trackBox.displayComponents = this._displayComponents;
1988
- const $trackBy = toObservable(this.trackBy);
2057
+ const $trackBy = toObservable(this.trackBy), $selectByClick = toObservable(this.selectByClick);
2058
+ $selectByClick.pipe(takeUntilDestroyed(), tap(v => {
2059
+ this._service.selectByClick = v;
2060
+ })).subscribe();
1989
2061
  $trackBy.pipe(takeUntilDestroyed(), tap(v => {
1990
2062
  this._trackBox.trackingPropertyName = v;
1991
2063
  })).subscribe();
1992
- 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)), $stickyMap = toObservable(this.stickyMap).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), $cacheVersion = toObservable(this._cacheVersion);
2064
+ 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), $cacheVersion = toObservable(this._cacheVersion);
1993
2065
  $isVertical.pipe(takeUntilDestroyed(), tap(v => {
1994
2066
  this._isVertical = v;
1995
2067
  const el = this._elementRef.nativeElement;
@@ -2028,14 +2100,14 @@ class NgVirtualListComponent {
2028
2100
  $dynamicSize.pipe(takeUntilDestroyed(), tap(dynamicSize => {
2029
2101
  this.listenCacheChangesIfNeed(dynamicSize);
2030
2102
  })).subscribe();
2031
- combineLatest([this.$initialized, $bounds, $items, $stickyMap, $scrollSize, $itemSize,
2103
+ combineLatest([this.$initialized, $bounds, $items, $itemConfigMap, $scrollSize, $itemSize,
2032
2104
  $bufferSize, $maxBufferSize, $snap, $isVertical, $dynamicSize, $enabledBufferOptimization, $cacheVersion,
2033
- ]).pipe(takeUntilDestroyed(), distinctUntilChanged(), filter(([initialized]) => !!initialized), switchMap(([, bounds, items, stickyMap, scrollSize, itemSize, bufferSize, maxBufferSize, snap, isVertical, dynamicSize, enabledBufferOptimization, cacheVersion,]) => {
2105
+ ]).pipe(takeUntilDestroyed(), distinctUntilChanged(), filter(([initialized]) => !!initialized), switchMap(([, bounds, items, itemConfigMap, scrollSize, itemSize, bufferSize, maxBufferSize, snap, isVertical, dynamicSize, enabledBufferOptimization, cacheVersion,]) => {
2034
2106
  let actualScrollSize = (this._isVertical ? this._container()?.nativeElement.scrollTop ?? 0 : this._container()?.nativeElement.scrollLeft) ?? 0;
2035
2107
  const { width, height } = bounds, opts = {
2036
2108
  bounds: { width, height }, dynamicSize, isVertical, itemSize,
2037
2109
  bufferSize, maxBufferSize, scrollSize: actualScrollSize, snap, enabledBufferOptimization,
2038
- }, { displayItems, totalSize } = this._trackBox.updateCollection(items, stickyMap, opts);
2110
+ }, { displayItems, totalSize } = this._trackBox.updateCollection(items, itemConfigMap, opts);
2039
2111
  this.resetBoundsSize(isVertical, totalSize);
2040
2112
  this.createDisplayComponentsIfNeed(displayItems);
2041
2113
  this.tracking();
@@ -2067,10 +2139,19 @@ class NgVirtualListComponent {
2067
2139
  this._service.$itemClick.pipe(takeUntilDestroyed(), tap(v => {
2068
2140
  this.onItemClick.emit(v);
2069
2141
  })).subscribe();
2070
- this._service.$selectedIds.pipe(takeUntilDestroyed(), tap(v => {
2071
- this.onSelect.emit(v);
2142
+ let isSelectedIdsFirstEmit = 0;
2143
+ this._service.$selectedIds.pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(v => {
2144
+ if (this.isSingleSelecting || (this.isMultiSelecting && isSelectedIdsFirstEmit >= 2)) {
2145
+ const curr = this.selectedIds();
2146
+ if ((this.isSingleSelecting && JSON.stringify(v) !== JSON.stringify(curr)) || (isSelectedIdsFirstEmit === 2 && JSON.stringify(v) !== JSON.stringify(curr)) || isSelectedIdsFirstEmit > 2) {
2147
+ this.onSelect.emit(v);
2148
+ }
2149
+ }
2150
+ if (isSelectedIdsFirstEmit < 3) {
2151
+ isSelectedIdsFirstEmit++;
2152
+ }
2072
2153
  })).subscribe();
2073
- $selectedIds.pipe(takeUntilDestroyed(), tap(v => {
2154
+ $selectedIds.pipe(takeUntilDestroyed(), distinctUntilChanged(), tap(v => {
2074
2155
  this._service.setSelectedIds(v);
2075
2156
  })).subscribe();
2076
2157
  }
@@ -2200,19 +2281,19 @@ class NgVirtualListComponent {
2200
2281
  if (container) {
2201
2282
  container.nativeElement.removeEventListener(SCROLL, this._onScrollHandler);
2202
2283
  }
2203
- const { width, height } = this._bounds() || { width: DEFAULT_LIST_SIZE, height: DEFAULT_LIST_SIZE }, stickyMap = this.stickyMap(), items = this.items(), isVertical = this._isVertical, delta = this._trackBox.delta, opts = {
2284
+ const { width, height } = this._bounds() || { width: DEFAULT_LIST_SIZE, height: DEFAULT_LIST_SIZE }, itemConfigMap = this.itemConfigMap(), items = this.items(), isVertical = this._isVertical, delta = this._trackBox.delta, opts = {
2204
2285
  bounds: { width, height }, collection: items, dynamicSize, isVertical: this._isVertical, itemSize,
2205
2286
  bufferSize: this.bufferSize(), maxBufferSize: this.maxBufferSize(),
2206
2287
  scrollSize: (isVertical ? container.nativeElement.scrollTop : container.nativeElement.scrollLeft) + delta,
2207
2288
  snap: this.snap(), fromItemId: id, enabledBufferOptimization: this.enabledBufferOptimization(),
2208
- }, scrollSize = this._trackBox.getItemPosition(id, stickyMap, opts), params = { [isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: scrollSize, behavior };
2289
+ }, scrollSize = this._trackBox.getItemPosition(id, itemConfigMap, opts), params = { [isVertical ? TOP_PROP_NAME : LEFT_PROP_NAME]: scrollSize, behavior };
2209
2290
  if (scrollSize === -1) {
2210
2291
  container.nativeElement.addEventListener(SCROLL, this._onScrollHandler);
2211
2292
  return;
2212
2293
  }
2213
2294
  this._trackBox.clearDelta();
2214
2295
  if (container) {
2215
- const { displayItems, totalSize } = this._trackBox.updateCollection(items, stickyMap, {
2296
+ const { displayItems, totalSize } = this._trackBox.updateCollection(items, itemConfigMap, {
2216
2297
  ...opts, scrollSize, fromItemId: isLastIteration ? undefined : id,
2217
2298
  }), delta = this._trackBox.delta;
2218
2299
  this._trackBox.clearDelta();
@@ -2220,7 +2301,7 @@ class NgVirtualListComponent {
2220
2301
  this.resetBoundsSize(isVertical, totalSize);
2221
2302
  this.createDisplayComponentsIfNeed(displayItems);
2222
2303
  this.tracking();
2223
- const _scrollSize = this._trackBox.getItemPosition(id, stickyMap, { ...opts, scrollSize: actualScrollSize, fromItemId: id });
2304
+ const _scrollSize = this._trackBox.getItemPosition(id, itemConfigMap, { ...opts, scrollSize: actualScrollSize, fromItemId: id });
2224
2305
  if (_scrollSize === -1) {
2225
2306
  container.nativeElement.addEventListener(SCROLL, this._onScrollHandler);
2226
2307
  return;
@@ -2334,7 +2415,7 @@ class NgVirtualListComponent {
2334
2415
  }
2335
2416
  }
2336
2417
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: NgVirtualListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2337
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: NgVirtualListComponent, isStandalone: true, selector: "ng-virtual-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, 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 }, stickyMap: { classPropertyName: "stickyMap", publicName: "stickyMap", 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 }, itemsOffset: { classPropertyName: "itemsOffset", publicName: "itemsOffset", 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" }, providers: [NgVirtualListService], viewQueries: [{ propertyName: "_snappedContainer", first: true, predicate: ["snapped"], descendants: true, isSignal: true }, { propertyName: "_container", first: true, predicate: ["container"], descendants: true, isSignal: true }, { propertyName: "_list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "_listContainerRef", first: true, predicate: ["renderersContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "_snapContainerRef", first: true, predicate: ["snapRendererContainer"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "@if (snap()) {\r\n <div #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n </div>\r\n}\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <div [attr.aria-orientation]=\"orientation\" #list part=\"list\" class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </div>\r\n</div>", styles: [":host{position:relative;display:block;width:400px;overflow:hidden}:host(.horizontal){height:48px}:host(.horizontal) .ngvl__list{display:inline-flex}:host(.horizontal) .ngvl__scroller{overflow:auto hidden}:host(.vertical) .ngvl__scroller{overflow:hidden auto}:host(.vertical){height:320px}.ngvl__scroller{overflow:auto;width:100%;height:100%}.ngvl__list-snapper{pointer-events:none;position:absolute;list-style:none;left:0;top:0;z-index:1}.ngvl__list{position:relative;list-style:none;padding:0;margin:0;width:100%;height:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
2418
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: NgVirtualListComponent, isStandalone: true, selector: "ng-virtual-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null }, selectByClick: { classPropertyName: "selectByClick", publicName: "selectByClick", 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 }, stickyMap: { classPropertyName: "stickyMap", publicName: "stickyMap", isSignal: true, isRequired: false, 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 }, itemsOffset: { classPropertyName: "itemsOffset", publicName: "itemsOffset", 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" }, providers: [NgVirtualListService], viewQueries: [{ propertyName: "_snappedContainer", first: true, predicate: ["snapped"], descendants: true, isSignal: true }, { propertyName: "_container", first: true, predicate: ["container"], descendants: true, isSignal: true }, { propertyName: "_list", first: true, predicate: ["list"], descendants: true, isSignal: true }, { propertyName: "_listContainerRef", first: true, predicate: ["renderersContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "_snapContainerRef", first: true, predicate: ["snapRendererContainer"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "@if (snap()) {\r\n <div #snapped part=\"snapped-item\" class=\"ngvl__list-snapper\">\r\n <ng-container #snapRendererContainer></ng-container>\r\n </div>\r\n}\r\n<div #container part=\"scroller\" class=\"ngvl__scroller\">\r\n <div [attr.aria-orientation]=\"orientation\" #list part=\"list\" class=\"ngvl__list\">\r\n <ng-container #renderersContainer></ng-container>\r\n </div>\r\n</div>", styles: [":host{position:relative;display:block;width:400px;overflow:hidden}:host(.horizontal){height:48px}:host(.horizontal) .ngvl__list{display:inline-flex}:host(.horizontal) .ngvl__scroller{overflow:auto hidden}:host(.vertical) .ngvl__scroller{overflow:hidden auto}:host(.vertical){height:320px}.ngvl__scroller{overflow:auto;width:100%;height:100%}.ngvl__list-snapper{pointer-events:none;position:absolute;list-style:none;left:0;top:0;z-index:1}.ngvl__list{position:relative;list-style:none;padding:0;margin:0;width:100%;height:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom });
2338
2419
  }
2339
2420
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: NgVirtualListComponent, decorators: [{
2340
2421
  type: Component,