@progress/kendo-angular-listbox 21.0.0-develop.2 → 21.0.0-develop.21

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.
@@ -4,7 +4,7 @@
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  /* eslint-disable @typescript-eslint/no-inferrable-types */
6
6
  /* eslint-disable @typescript-eslint/no-explicit-any */
7
- import { ChangeDetectorRef, Component, ContentChild, ElementRef, EventEmitter, HostBinding, Input, isDevMode, NgZone, Output, QueryList, Renderer2, ViewChild, ViewChildren } from '@angular/core';
7
+ import { Component, ContentChild, ElementRef, EventEmitter, HostBinding, Input, isDevMode, NgZone, Output, QueryList, Renderer2, ViewChild, ViewChildren } from '@angular/core';
8
8
  import { validatePackage } from '@progress/kendo-licensing';
9
9
  import { Subscription } from 'rxjs';
10
10
  import { packageMetadata } from './package-metadata';
@@ -20,7 +20,7 @@ import { caretAltLeftIcon, caretAltRightIcon } from '@progress/kendo-svg-icons';
20
20
  import { ItemSelectableDirective } from './item-selectable.directive';
21
21
  import { NgIf, NgFor } from '@angular/common';
22
22
  import { LocalizedMessagesDirective } from './localization/localized-messages.directive';
23
- import { TemplateContextDirective } from '@progress/kendo-angular-common';
23
+ import { isPresent, TemplateContextDirective } from '@progress/kendo-angular-common';
24
24
  import * as i0 from "@angular/core";
25
25
  import * as i1 from "./keyboard-navigation.service";
26
26
  import * as i2 from "./selection.service";
@@ -62,7 +62,6 @@ export class ListBoxComponent {
62
62
  renderer;
63
63
  zone;
64
64
  localization;
65
- changeDetector;
66
65
  /**
67
66
  * @hidden
68
67
  */
@@ -95,6 +94,18 @@ export class ListBoxComponent {
95
94
  * Specifies the field of the data item that provides the text content of the nodes.
96
95
  */
97
96
  textField;
97
+ /**
98
+ * Sets the selection mode of the ListBox.
99
+ *
100
+ * @default 'single'
101
+ */
102
+ set selectable(mode) {
103
+ this._selectable = mode;
104
+ this.selectionService.selectionMode = mode;
105
+ }
106
+ get selectable() {
107
+ return this._selectable;
108
+ }
98
109
  /**
99
110
  * Specifies the data that the ListBox displays.
100
111
  *
@@ -117,6 +128,8 @@ export class ListBoxComponent {
117
128
  /**
118
129
  * Configures the toolbar of the ListBox.
119
130
  * Specifies whether to display a toolbar and which tools and position to use.
131
+ *
132
+ * @default false
120
133
  */
121
134
  set toolbar(config) {
122
135
  let position = DEFAULT_TOOLBAR_POSITION;
@@ -155,7 +168,7 @@ export class ListBoxComponent {
155
168
  /**
156
169
  * Fires when you click a ListBox item.
157
170
  */
158
- actionClick = new EventEmitter();
171
+ action = new EventEmitter();
159
172
  /**
160
173
  * @hidden
161
174
  */
@@ -175,7 +188,7 @@ export class ListBoxComponent {
175
188
  /**
176
189
  * @hidden
177
190
  */
178
- selectedTools = allTools;
191
+ selectedTools = [];
179
192
  /**
180
193
  * @hidden
181
194
  */
@@ -203,15 +216,15 @@ export class ListBoxComponent {
203
216
  localizationSubscription;
204
217
  _size = DEFAULT_SIZE;
205
218
  subs = new Subscription();
206
- shouldFireFocusIn = true;
207
- constructor(keyboardNavigationService, selectionService, hostElement, renderer, zone, localization, changeDetector) {
219
+ shouldFireFocusIn = false;
220
+ _selectable = 'single';
221
+ constructor(keyboardNavigationService, selectionService, hostElement, renderer, zone, localization) {
208
222
  this.keyboardNavigationService = keyboardNavigationService;
209
223
  this.selectionService = selectionService;
210
224
  this.hostElement = hostElement;
211
225
  this.renderer = renderer;
212
226
  this.zone = zone;
213
227
  this.localization = localization;
214
- this.changeDetector = changeDetector;
215
228
  validatePackage(packageMetadata);
216
229
  this.setToolbarClass(DEFAULT_TOOLBAR_POSITION);
217
230
  this.setSizingClass(this.size);
@@ -224,9 +237,6 @@ export class ListBoxComponent {
224
237
  // This allows us to know to which parent Listbox the child Listbox is connected to
225
238
  this.childListbox.parentListbox = this;
226
239
  }
227
- if (this.selectedIndex) {
228
- this.keyboardNavigationService.focusedToolIndex = this.selectedIndex;
229
- }
230
240
  this.localizationSubscription = this.localization.changes.subscribe(({ rtl }) => {
231
241
  this.direction = rtl ? 'rtl' : 'ltr';
232
242
  });
@@ -251,10 +261,10 @@ export class ListBoxComponent {
251
261
  const isListboxParentAndChild = !!(this.parentListbox && this.childListbox);
252
262
  const isListboxParent = !!(this.childListbox || (!this.childListbox && !this.parentListbox));
253
263
  if (isListboxChild || (isListboxParentAndChild && isActionTransferFrom)) {
254
- this.parentListbox.actionClick.next(actionName);
264
+ this.parentListbox.action.next(actionName);
255
265
  }
256
266
  else if (isListboxParent || (isListboxParentAndChild && !isActionTransferFrom)) {
257
- this.actionClick.next(actionName);
267
+ this.action.next(actionName);
258
268
  }
259
269
  const toolsRef = this.tools.toArray() || this.parentListbox.tools.toArray();
260
270
  const focusedToolIndex = toolsRef.findIndex(elem => elem.nativeElement === document.activeElement);
@@ -267,11 +277,22 @@ export class ListBoxComponent {
267
277
  navService.changeTabindex(prevTool, currentTool);
268
278
  }
269
279
  }
280
+ /**
281
+ * Selects multiple ListBox nodes programmatically.
282
+ */
283
+ select(indices) {
284
+ const validIndices = indices.filter(index => index >= 0 && index < this.data.length);
285
+ this.selectionService.setSelectedIndices(validIndices);
286
+ }
270
287
  /**
271
288
  * Selects a ListBox node programmatically.
289
+ *
290
+ * @hidden
272
291
  */
273
292
  selectItem(index) {
274
- this.selectionService.selectedIndex = index;
293
+ if (index >= 0 && index < this.data.length) {
294
+ this.select([index]);
295
+ }
275
296
  }
276
297
  /**
277
298
  * Clears the ListBox selection programmatically.
@@ -280,10 +301,10 @@ export class ListBoxComponent {
280
301
  this.selectionService.clearSelection();
281
302
  }
282
303
  /**
283
- * Gets the index of the currently selected item in the ListBox.
304
+ * Gets the indexes of the currently selected items in the ListBox.
284
305
  */
285
- get selectedIndex() {
286
- return this.selectionService.selectedIndex;
306
+ get selectedIndices() {
307
+ return this.selectionService.selectedIndices;
287
308
  }
288
309
  /**
289
310
  * @hidden
@@ -326,36 +347,81 @@ export class ListBoxComponent {
326
347
  this.caretAltLeftIcon :
327
348
  icon;
328
349
  }
329
- onClickEvent(prevIndex, index) {
330
- this.shouldFireFocusIn = false;
331
- this.selectionChange.next({ index, prevIndex: this.keyboardNavigationService.selectedListboxItemIndex });
332
- this.keyboardNavigationService.selectedListboxItemIndex = index;
333
- this.keyboardNavigationService.focusedListboxItemIndex = index;
334
- this.zone.onStable.pipe(take(1)).subscribe(() => {
335
- const listboxItems = this.listboxItems.toArray();
336
- const previousItem = prevIndex ? listboxItems[prevIndex].nativeElement : listboxItems[0].nativeElement;
337
- const currentItem = listboxItems[index].nativeElement;
338
- this.keyboardNavigationService.changeTabindex(previousItem, currentItem);
339
- });
340
- this.zone.onStable.pipe(take(1)).subscribe(() => {
341
- this.shouldFireFocusIn = true;
342
- });
343
- }
344
350
  initSubscriptions(navService, hostEl, toolsRef) {
345
351
  this.subs.add(navService.onShiftSelectedItem.subscribe((actionToPerform) => this.performAction(actionToPerform)));
346
352
  this.subs.add(navService.onTransferAllEvent.subscribe((actionToPerform) => this.performAction(actionToPerform)));
347
- this.subs.add(this.selectionService.onSelect.subscribe((e) => this.onClickEvent(e.prevIndex, e.index)));
353
+ this.subs.add(this.selectionService.onSelect.subscribe((event) => {
354
+ this.shouldFireFocusIn = false;
355
+ this.selectionChange.next(event);
356
+ const newFocusIndex = isPresent(this.selectionService.rangeSelectionTargetIndex)
357
+ ? this.selectionService.rangeSelectionTargetIndex
358
+ : this.selectionService.lastSelectedOrUnselectedIndex;
359
+ if (newFocusIndex !== null && newFocusIndex !== undefined) {
360
+ const listboxItems = this.listboxItems.toArray();
361
+ const previousItem = listboxItems[navService.focusedListboxItemIndex]?.nativeElement;
362
+ const currentItem = listboxItems[newFocusIndex]?.nativeElement;
363
+ if (previousItem !== currentItem && currentItem) {
364
+ navService.changeTabindex(previousItem, currentItem, false);
365
+ navService.focusedListboxItemIndex = newFocusIndex;
366
+ navService.selectedListboxItemIndex = newFocusIndex;
367
+ }
368
+ }
369
+ this.zone.runOutsideAngular(() => setTimeout(() => {
370
+ this.shouldFireFocusIn = true;
371
+ }));
372
+ }));
348
373
  this.subs.add(navService.onDeleteEvent.subscribe((index) => this.onDeleteEvent(index, navService)));
349
374
  this.subs.add(navService.onMoveSelectedItem.subscribe((dir) => this.performAction(dir)));
375
+ this.subs.add(navService.onSelectAll.subscribe(() => {
376
+ if (this.selectable === 'multiple') {
377
+ const previousSelection = [...this.selectionService.selectedIndices];
378
+ const allSelected = this.selectionService.areAllSelected(this.data.length);
379
+ if (allSelected) {
380
+ this.selectionService.clearSelection();
381
+ this.selectionChange.next({
382
+ selectedIndices: null,
383
+ deselectedIndices: previousSelection.length > 0 ? previousSelection : null
384
+ });
385
+ }
386
+ else {
387
+ this.selectionService.selectAll(this.data.length);
388
+ const selectedIndices = this.selectionService.selectedIndices.filter(i => !previousSelection.includes(i));
389
+ this.selectionChange.next({
390
+ selectedIndices: selectedIndices.length > 0 ? selectedIndices : null,
391
+ deselectedIndices: null
392
+ });
393
+ }
394
+ }
395
+ }));
396
+ this.subs.add(navService.onSelectToEnd.subscribe(({ direction }) => {
397
+ if (this.selectable === 'multiple') {
398
+ this.shouldFireFocusIn = false;
399
+ const previousSelection = [...this.selectionService.selectedIndices];
400
+ const targetIndex = direction === 'home' ? 0 : this.data.length - 1;
401
+ this.selectionService.selectRange(targetIndex);
402
+ const selectedIndices = this.selectionService.selectedIndices.filter(i => !previousSelection.includes(i));
403
+ const deselectedIndices = previousSelection.filter(i => !this.selectionService.selectedIndices.includes(i));
404
+ this.selectionChange.next({
405
+ selectedIndices: selectedIndices.length > 0 ? selectedIndices : null,
406
+ deselectedIndices: deselectedIndices.length > 0 ? deselectedIndices : null
407
+ });
408
+ const listboxItems = this.listboxItems.toArray();
409
+ const currentItem = listboxItems[navService.focusedListboxItemIndex]?.nativeElement;
410
+ const targetItem = listboxItems[targetIndex]?.nativeElement;
411
+ navService.changeTabindex(currentItem, targetItem);
412
+ navService.focusedListboxItemIndex = targetIndex;
413
+ this.zone.runOutsideAngular(() => setTimeout(() => {
414
+ this.shouldFireFocusIn = true;
415
+ }));
416
+ }
417
+ }));
350
418
  if (this.listboxElement) {
351
419
  this.subs.add(this.renderer.listen(this.listboxElement.nativeElement, 'focusin', (event) => this.onFocusIn(event)));
352
420
  }
353
421
  this.subs.add(this.renderer.listen(hostEl, 'keydown', (event) => navService.onKeyDown(event, toolsRef, this.selectedTools, this.childListbox, this.parentListbox, this.listboxItems.toArray())));
354
- this.subs.add(navService.onSelectionChange.subscribe((indexes) => {
355
- const { prevIndex, index } = indexes;
356
- this.selectionService.selectedIndex = index;
357
- this.selectionChange.next({ index, prevIndex });
358
- this.changeDetector.markForCheck();
422
+ this.subs.add(navService.onSelectionChange.subscribe((event) => {
423
+ const { index, ctrlKey, shiftKey } = event;
424
+ this.selectionService.select(index, ctrlKey, shiftKey);
359
425
  }));
360
426
  }
361
427
  onFocusIn(event) {
@@ -366,8 +432,15 @@ export class ListBoxComponent {
366
432
  if (index === -1) {
367
433
  return;
368
434
  }
369
- this.selectionService.selectedIndex = index;
370
- this.selectionChange.next({ index, prevIndex: null });
435
+ const previousSelection = [...this.selectionService.selectedIndices];
436
+ this.selectionService.addToSelectedIndices(index);
437
+ navService.focusedListboxItemIndex = index;
438
+ navService.selectedListboxItemIndex = index;
439
+ const deselected = previousSelection.filter(i => i !== index);
440
+ this.selectionChange.next({
441
+ selectedIndices: [index],
442
+ deselectedIndices: deselected.length > 0 ? deselected : null
443
+ });
371
444
  const previousItem = items[navService.selectedListboxItemIndex]?.nativeElement;
372
445
  const currentItem = items[index]?.nativeElement;
373
446
  this.renderer.setAttribute(previousItem, 'tabindex', '-1');
@@ -409,17 +482,20 @@ export class ListBoxComponent {
409
482
  }
410
483
  }
411
484
  onDeleteEvent(index, navService) {
412
- this.selectionService.selectedIndex = index;
485
+ this.selectionService.addToSelectedIndices(index);
413
486
  this.performAction('remove');
414
487
  const listboxItems = this.listboxItems.toArray();
415
488
  const setIndex = index + 1 === listboxItems.length ?
416
489
  { index: index - 1, tabindex: index - 1 } : { index, tabindex: index + 1 };
417
490
  navService.changeTabindex(null, listboxItems[setIndex['tabindex']]?.nativeElement);
418
- this.selectionChange.next({ index: setIndex['index'], prevIndex: null });
491
+ this.selectionChange.next({
492
+ selectedIndices: [setIndex['index']],
493
+ deselectedIndices: null
494
+ });
419
495
  navService.selectedListboxItemIndex = setIndex['index'];
420
496
  navService.focusedListboxItemIndex = setIndex['index'];
421
497
  navService.focusedListboxItem = setIndex['index'];
422
- this.selectionService.selectedIndex = setIndex['index'];
498
+ this.selectionService.selectedIndices = [setIndex['index']];
423
499
  }
424
500
  setToolbarClass(pos) {
425
501
  Object.keys(actionsClasses).forEach((className) => {
@@ -434,8 +510,8 @@ export class ListBoxComponent {
434
510
  setSizingClass(size) {
435
511
  this.renderer.addClass(this.hostElement.nativeElement, `k-listbox-${sizeClassMap[size]}`);
436
512
  }
437
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListBoxComponent, deps: [{ token: i1.KeyboardNavigationService }, { token: i2.ListBoxSelectionService }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: i3.LocalizationService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
438
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ListBoxComponent, isStandalone: true, selector: "kendo-listbox", inputs: { textField: "textField", data: "data", size: "size", toolbar: "toolbar", listboxLabel: "listboxLabel", listboxToolbarLabel: "listboxToolbarLabel", itemDisabled: "itemDisabled" }, outputs: { selectionChange: "selectionChange", actionClick: "actionClick", getChildListbox: "getChildListbox" }, host: { properties: { "class.k-listbox": "this.listboxClassName", "attr.dir": "this.direction" } }, providers: [
513
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListBoxComponent, deps: [{ token: i1.KeyboardNavigationService }, { token: i2.ListBoxSelectionService }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: i3.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
514
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: ListBoxComponent, isStandalone: true, selector: "kendo-listbox", inputs: { textField: "textField", selectable: "selectable", data: "data", size: "size", toolbar: "toolbar", listboxLabel: "listboxLabel", listboxToolbarLabel: "listboxToolbarLabel", itemDisabled: "itemDisabled" }, outputs: { selectionChange: "selectionChange", action: "action", getChildListbox: "getChildListbox" }, host: { properties: { "class.k-listbox": "this.listboxClassName", "attr.dir": "this.direction" } }, providers: [
439
515
  ListBoxSelectionService,
440
516
  KeyboardNavigationService,
441
517
  LocalizationService,
@@ -502,16 +578,16 @@ export class ListBoxComponent {
502
578
  class="k-list-ul"
503
579
  role="listbox"
504
580
  [attr.aria-label]="listboxLabel"
505
- [attr.aria-multiselectable]="false"
581
+ [attr.aria-multiselectable]="selectable === 'multiple'"
506
582
  >
507
583
  <li
508
584
  #listboxItems
509
585
  *ngFor="let item of data; let i = index"
510
586
  kendoListBoxItemSelectable
511
587
  class="k-list-item"
512
- [attr.tabindex]="i === 0 ? '0' : '-1'"
588
+ [attr.tabindex]="i === keyboardNavigationService.focusedListboxItemIndex ? '0' : '-1'"
513
589
  role="option"
514
- [attr.aria-selected]="selectedIndex === i"
590
+ [attr.aria-selected]="selectedIndices.indexOf(i) >= 0"
515
591
  [index]="i"
516
592
  [class.k-disabled]="itemDisabled(item)"
517
593
  >
@@ -609,16 +685,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
609
685
  class="k-list-ul"
610
686
  role="listbox"
611
687
  [attr.aria-label]="listboxLabel"
612
- [attr.aria-multiselectable]="false"
688
+ [attr.aria-multiselectable]="selectable === 'multiple'"
613
689
  >
614
690
  <li
615
691
  #listboxItems
616
692
  *ngFor="let item of data; let i = index"
617
693
  kendoListBoxItemSelectable
618
694
  class="k-list-item"
619
- [attr.tabindex]="i === 0 ? '0' : '-1'"
695
+ [attr.tabindex]="i === keyboardNavigationService.focusedListboxItemIndex ? '0' : '-1'"
620
696
  role="option"
621
- [attr.aria-selected]="selectedIndex === i"
697
+ [attr.aria-selected]="selectedIndices.indexOf(i) >= 0"
622
698
  [index]="i"
623
699
  [class.k-disabled]="itemDisabled(item)"
624
700
  >
@@ -646,7 +722,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
646
722
  standalone: true,
647
723
  imports: [LocalizedMessagesDirective, NgIf, NgFor, ButtonComponent, ItemSelectableDirective, TemplateContextDirective]
648
724
  }]
649
- }], ctorParameters: () => [{ type: i1.KeyboardNavigationService }, { type: i2.ListBoxSelectionService }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: i3.LocalizationService }, { type: i0.ChangeDetectorRef }], propDecorators: { listboxClassName: [{
725
+ }], ctorParameters: () => [{ type: i1.KeyboardNavigationService }, { type: i2.ListBoxSelectionService }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: i3.LocalizationService }], propDecorators: { listboxClassName: [{
650
726
  type: HostBinding,
651
727
  args: ['class.k-listbox']
652
728
  }], direction: [{
@@ -669,6 +745,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
669
745
  args: ['tools']
670
746
  }], textField: [{
671
747
  type: Input
748
+ }], selectable: [{
749
+ type: Input
672
750
  }], data: [{
673
751
  type: Input
674
752
  }], size: [{
@@ -683,7 +761,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
683
761
  type: Input
684
762
  }], selectionChange: [{
685
763
  type: Output
686
- }], actionClick: [{
764
+ }], action: [{
687
765
  type: Output
688
766
  }], getChildListbox: [{
689
767
  type: Output
@@ -10,7 +10,7 @@ export const packageMetadata = {
10
10
  productName: 'Kendo UI for Angular',
11
11
  productCode: 'KENDOUIANGULAR',
12
12
  productCodes: ['KENDOUIANGULAR'],
13
- publishDate: 1761753096,
14
- version: '21.0.0-develop.2',
13
+ publishDate: 1762427032,
14
+ version: '21.0.0-develop.21',
15
15
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/?utm_medium=product&utm_source=kendoangular&utm_campaign=kendo-ui-angular-purchase-license-keys-warning'
16
16
  };
@@ -0,0 +1,5 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2025 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ export {};
@@ -8,17 +8,138 @@ import * as i0 from "@angular/core";
8
8
  * @hidden
9
9
  */
10
10
  export class ListBoxSelectionService {
11
+ selectedIndices = [];
12
+ selectionMode = 'single';
13
+ lastSelectedOrUnselectedIndex = null;
14
+ rangeSelectionTargetIndex = null;
15
+ rangeSelectionAnchorIndex = null;
11
16
  onSelect = new EventEmitter();
12
- selectedIndex = null;
13
- select(index) {
14
- this.onSelect.next({ index: index, prevIndex: this.selectedIndex });
15
- this.selectedIndex = index;
17
+ select(index, ctrlKey = false, shiftKey = false) {
18
+ const previousSelection = [...this.selectedIndices];
19
+ let selectedIndices = [];
20
+ let deselectedIndices = null;
21
+ const previousTargetIndex = this.rangeSelectionTargetIndex;
22
+ if (this.selectionMode === 'single') {
23
+ if (ctrlKey) {
24
+ const isSelected = this.isSelected(index);
25
+ if (isSelected) {
26
+ this.selectedIndices = [];
27
+ deselectedIndices = [index];
28
+ }
29
+ else {
30
+ this.selectedIndices = [index];
31
+ selectedIndices = [index];
32
+ if (previousSelection.length > 0) {
33
+ deselectedIndices = previousSelection;
34
+ }
35
+ }
36
+ this.lastSelectedOrUnselectedIndex = index;
37
+ }
38
+ else {
39
+ this.selectedIndices = [index];
40
+ selectedIndices = [index];
41
+ this.lastSelectedOrUnselectedIndex = index;
42
+ this.rangeSelectionAnchorIndex = index;
43
+ if (previousSelection.length > 0 && previousSelection[0] !== index) {
44
+ deselectedIndices = previousSelection;
45
+ }
46
+ }
47
+ }
48
+ else if (this.selectionMode === 'multiple') {
49
+ if (shiftKey) {
50
+ let anchorIndex = this.rangeSelectionAnchorIndex ?? this.lastSelectedOrUnselectedIndex ?? 0;
51
+ if (index === anchorIndex) {
52
+ this.selectedIndices = [anchorIndex];
53
+ this.rangeSelectionTargetIndex = index;
54
+ selectedIndices = this.selectedIndices.filter(i => !previousSelection.includes(i));
55
+ const nowDeselected = previousSelection.filter(i => !this.selectedIndices.includes(i));
56
+ deselectedIndices = nowDeselected.length > 0 ? nowDeselected : null;
57
+ }
58
+ else {
59
+ if (previousTargetIndex !== null && previousTargetIndex !== anchorIndex) {
60
+ const previousDirection = previousTargetIndex > anchorIndex ? 'down' : 'up';
61
+ const currentDirection = index > anchorIndex ? 'down' : 'up';
62
+ if (previousDirection !== currentDirection) {
63
+ this.rangeSelectionAnchorIndex = previousTargetIndex;
64
+ anchorIndex = previousTargetIndex;
65
+ }
66
+ }
67
+ const startIndex = Math.min(anchorIndex, index);
68
+ const endIndex = Math.max(anchorIndex, index);
69
+ this.selectedIndices = [];
70
+ for (let i = startIndex; i <= endIndex; i++) {
71
+ this.selectedIndices.push(i);
72
+ }
73
+ this.rangeSelectionTargetIndex = index;
74
+ selectedIndices = this.selectedIndices.filter(i => !previousSelection.includes(i));
75
+ const nowDeselected = previousSelection.filter(i => !this.selectedIndices.includes(i));
76
+ deselectedIndices = nowDeselected.length > 0 ? nowDeselected : null;
77
+ }
78
+ }
79
+ else if (ctrlKey) {
80
+ const indexInSelection = this.selectedIndices.indexOf(index);
81
+ if (indexInSelection === -1) {
82
+ this.selectedIndices.push(index);
83
+ selectedIndices = [index];
84
+ }
85
+ else {
86
+ this.selectedIndices.splice(indexInSelection, 1);
87
+ deselectedIndices = [index];
88
+ }
89
+ this.lastSelectedOrUnselectedIndex = index;
90
+ this.rangeSelectionAnchorIndex = index;
91
+ this.rangeSelectionTargetIndex = index;
92
+ }
93
+ else {
94
+ this.selectedIndices = [index];
95
+ selectedIndices = [index];
96
+ this.lastSelectedOrUnselectedIndex = index;
97
+ this.rangeSelectionAnchorIndex = index;
98
+ this.rangeSelectionTargetIndex = index;
99
+ const nowDeselected = previousSelection.filter(i => i !== index);
100
+ deselectedIndices = nowDeselected.length > 0 ? nowDeselected : null;
101
+ }
102
+ }
103
+ this.onSelect.next({
104
+ selectedIndices: selectedIndices.length > 0 ? selectedIndices : null,
105
+ deselectedIndices
106
+ });
107
+ }
108
+ selectRange(targetIndex) {
109
+ const anchorIndex = this.lastSelectedOrUnselectedIndex ?? 0;
110
+ const startIndex = Math.min(anchorIndex, targetIndex);
111
+ const endIndex = Math.max(anchorIndex, targetIndex);
112
+ this.selectedIndices = [];
113
+ for (let i = startIndex; i <= endIndex; i++) {
114
+ this.selectedIndices.push(i);
115
+ }
116
+ }
117
+ setSelectedIndices(indices) {
118
+ this.selectedIndices = [...indices];
119
+ }
120
+ addToSelectedIndices(index) {
121
+ if (this.selectionMode === 'single') {
122
+ this.selectedIndices = [index];
123
+ }
124
+ else if (this.selectedIndices.indexOf(index) === -1) {
125
+ this.selectedIndices = [...this.selectedIndices, index];
126
+ }
127
+ }
128
+ selectAll(totalItems) {
129
+ if (this.selectionMode === 'multiple') {
130
+ this.selectedIndices = Array.from({ length: totalItems }, (_, i) => i);
131
+ }
132
+ }
133
+ areAllSelected(totalItems) {
134
+ return this.selectedIndices.length === totalItems && totalItems > 0;
16
135
  }
17
136
  isSelected(index) {
18
- return index === this.selectedIndex;
137
+ return this.selectedIndices.indexOf(index) !== -1;
19
138
  }
20
139
  clearSelection() {
21
- this.selectedIndex = null;
140
+ this.selectedIndices = [];
141
+ this.lastSelectedOrUnselectedIndex = null;
142
+ this.rangeSelectionAnchorIndex = null;
22
143
  }
23
144
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListBoxSelectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
24
145
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ListBoxSelectionService });