@progress/kendo-angular-grid 18.4.1-develop.2 → 18.5.0-develop.1

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.
@@ -13,6 +13,7 @@ export declare class DomEventsService {
13
13
  cellMouseup: EventEmitter<any>;
14
14
  click: EventEmitter<any>;
15
15
  keydown: EventEmitter<any>;
16
+ shiftKeyup: EventEmitter<any>;
16
17
  focus: EventEmitter<any>;
17
18
  focusIn: EventEmitter<any>;
18
19
  focusOut: EventEmitter<any>;
@@ -13,6 +13,7 @@ export class DomEventsService {
13
13
  cellMouseup = new EventEmitter();
14
14
  click = new EventEmitter();
15
15
  keydown = new EventEmitter();
16
+ shiftKeyup = new EventEmitter();
16
17
  focus = new EventEmitter();
17
18
  focusIn = new EventEmitter();
18
19
  focusOut = new EventEmitter();
@@ -1990,6 +1990,11 @@ export class GridComponent {
1990
1990
  const keydownSubscription = this.renderer.listen(wrapper, 'keydown', (args) => {
1991
1991
  this.domEvents.keydown.emit(args);
1992
1992
  });
1993
+ const shiftKeyupSubscription = this.renderer.listen(wrapper, 'keyup', (args) => {
1994
+ if (args.key === 'Shift') {
1995
+ this.domEvents.shiftKeyup.emit(args);
1996
+ }
1997
+ });
1993
1998
  // focusIn and focusOut are relative to the element with ARIA role "grid"
1994
1999
  let focused = false;
1995
2000
  const focusInSubscription = this.renderer.listen(ariaRoot, 'focusin', (args) => {
@@ -2004,6 +2009,7 @@ export class GridComponent {
2004
2009
  const outside = !closest(next, (node) => node === ariaRoot);
2005
2010
  if (outside) {
2006
2011
  this.domEvents.focusOut.emit(args);
2012
+ this.domEvents.shiftKeyup.emit(args);
2007
2013
  focused = false;
2008
2014
  }
2009
2015
  });
@@ -2014,6 +2020,7 @@ export class GridComponent {
2014
2020
  windowBlurSubscription();
2015
2021
  clickSubscription();
2016
2022
  keydownSubscription();
2023
+ shiftKeyupSubscription();
2017
2024
  focusInSubscription();
2018
2025
  focusOutSubscription();
2019
2026
  };
@@ -171,6 +171,8 @@ export class NavigationService {
171
171
  tableIsNavigable = false;
172
172
  toolbarIsNavigable = false;
173
173
  lastCellRowIndex;
174
+ isShiftPressed = false;
175
+ currentSelection = [];
174
176
  get activeDataRow() {
175
177
  return Math.max(0, this.activeRowIndex - this.meta.headerRows);
176
178
  }
@@ -215,6 +217,10 @@ export class NavigationService {
215
217
  .subscribe(() => this.cursor.reset(0, 0)));
216
218
  this.subs.add(this.domEvents.keydown
217
219
  .subscribe(args => this.onKeydown(args)));
220
+ this.subs.add(this.domEvents.shiftKeyup
221
+ .subscribe(() => {
222
+ this.isShiftPressed = false;
223
+ }));
218
224
  this.subs.add(this.domEvents.keydown.pipe(filter(args => args.keyCode === Keys.Tab && this.mode === 2 /* NavigationMode.Content */), switchMapTo(this.domEvents.focusOut.pipe(takeUntil(
219
225
  // Timeout if focusOut doesn't fire very soon
220
226
  interval(0).pipe(take(1))))))
@@ -452,12 +458,23 @@ export class NavigationService {
452
458
  let step = modifier ? 5 : 1;
453
459
  const rowspan = +args.target?.getAttribute('rowspan');
454
460
  let rowspanOffset = 0;
461
+ let startNewSelection = false;
462
+ const allowMultipleRanges = (this.ctx.grid.selectionService.active && this.ctx.grid.selectableSettings?.multipleRanges) ||
463
+ (this.ctx.grid.cellSelectionService.active && this.ctx.grid.cellSelectionService?.options?.multipleRanges);
464
+ if (!allowMultipleRanges) {
465
+ this.currentSelection = [];
466
+ }
455
467
  if (!this.onCellKeydown(args)) {
456
468
  return;
457
469
  }
458
470
  const row = this.cursor.row;
459
471
  const dir = args.keyCode === Keys.ArrowDown ? 'Down' : 'Up';
460
472
  const right = args.keyCode === Keys.ArrowRight;
473
+ const isArrowKey = args.code === 'ArrowDown' || args.code === 'ArrowUp' || args.code === 'ArrowLeft' || args.code === 'ArrowRight';
474
+ if (!this.isShiftPressed && args.shiftKey && isArrowKey) {
475
+ startNewSelection = true;
476
+ this.isShiftPressed = true;
477
+ }
461
478
  switch (args.keyCode) {
462
479
  case Keys.ArrowDown:
463
480
  case Keys.ArrowUp:
@@ -470,9 +487,10 @@ export class NavigationService {
470
487
  return;
471
488
  }
472
489
  preventDefault = this.cursor[`move${dir}`](step);
490
+ const preserveCurrentSelection = startNewSelection && allowMultipleRanges;
473
491
  if (this.activeRow?.dataItem) {
474
492
  const sign = dir === 'Down' ? 1 : -1;
475
- this.handleVerticalArrowSelection(sign * step);
493
+ this.handleVerticalArrowSelection(sign * step, preserveCurrentSelection);
476
494
  }
477
495
  }
478
496
  else {
@@ -491,7 +509,8 @@ export class NavigationService {
491
509
  return;
492
510
  }
493
511
  preventDefault = this[`moveCursor${right ? 'Fwd' : 'Bwd'}`]();
494
- this.handleHorizontalArrowSelection(args);
512
+ const preserveCurrentSelection = startNewSelection && allowMultipleRanges;
513
+ this.handleHorizontalArrowSelection(args, preserveCurrentSelection);
495
514
  }
496
515
  else {
497
516
  preventDefault = this[`moveCursor${right ? 'Fwd' : 'Bwd'}`]();
@@ -694,7 +713,7 @@ export class NavigationService {
694
713
  this.leaveCell();
695
714
  this.cursor.reset();
696
715
  }
697
- handleVerticalArrowSelection(args) {
716
+ handleVerticalArrowSelection(args, preserveSelection) {
698
717
  const cellSelectionEnabled = this.ctx.grid.cellSelectionService.active;
699
718
  const rowSelectionEnabled = this.ctx.grid.selectionService.active && !this.ctx.grid.selectableSettings.checkboxOnly;
700
719
  if (cellSelectionEnabled || rowSelectionEnabled) {
@@ -704,14 +723,15 @@ export class NavigationService {
704
723
  const dataItem = selectionService.settings.view.at(rowIdx);
705
724
  const item = { index: this.activeRow.dataRowIndex, data: dataItem, column: this.ctx.grid.columnsContainer.leafColumnsToRender[colIdx] };
706
725
  if (selectionService.options.mode === 'multiple') {
707
- cellSelectionEnabled ? this.handleMultipleArrowCellSelection(item) : this.handleMultipleArrowRowSelection(item);
726
+ const startRowIndex = this.activeRow.dataRowIndex - args;
727
+ cellSelectionEnabled ? this.handleMultipleArrowCellSelection(item, preserveSelection, startRowIndex, colIdx) : this.handleMultipleArrowRowSelection(item, preserveSelection, startRowIndex);
708
728
  }
709
729
  else {
710
730
  selectionService.handleClick(item, args);
711
731
  }
712
732
  }
713
733
  }
714
- handleHorizontalArrowSelection(args) {
734
+ handleHorizontalArrowSelection(args, preserveSelection) {
715
735
  const cellSelectionEnabled = this.ctx.grid.cellSelectionService.active;
716
736
  if (cellSelectionEnabled) {
717
737
  const selectionService = this.ctx.grid[cellSelectionEnabled ? 'cellSelectionService' : 'selectionService'];
@@ -723,27 +743,37 @@ export class NavigationService {
723
743
  return;
724
744
  }
725
745
  if (selectionService.options.mode === 'multiple') {
726
- this.handleMultipleArrowCellSelection(item);
746
+ const startColumnIndex = args.key === 'ArrowRight' ? colIdx - 1 : colIdx + 1;
747
+ this.handleMultipleArrowCellSelection(item, preserveSelection, row.dataRowIndex, startColumnIndex);
727
748
  }
728
749
  else {
729
750
  selectionService.handleClick(item, args);
730
751
  }
731
752
  }
732
753
  }
733
- handleMultipleArrowCellSelection(item) {
754
+ handleMultipleArrowCellSelection(item, preserveSelection, startRow, startColumn) {
734
755
  const cellSelectionService = this.ctx.grid.cellSelectionService;
735
- const startRowIndex = Math.min(cellSelectionService.lastSelectionItemRowIndex, item.index);
736
- const startColIndex = Math.min(cellSelectionService.lastSelectionItemColIndex, item.column.leafIndex);
737
- const endRowIndex = Math.max(cellSelectionService.lastSelectionItemRowIndex, item.index);
738
- const endColIndex = Math.max(cellSelectionService.lastSelectionItemColIndex, item.column.leafIndex);
739
- const ev = cellSelectionService.selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex);
756
+ const startRowIndex = preserveSelection ? startRow : Math.min(cellSelectionService.lastSelectionItemRowIndex, item.index);
757
+ const startColIndex = preserveSelection ? startColumn : Math.min(cellSelectionService.lastSelectionItemColIndex, item.column.leafIndex);
758
+ const endRowIndex = preserveSelection ? item.index : Math.max(cellSelectionService.lastSelectionItemRowIndex, item.index);
759
+ const endColIndex = preserveSelection ? item.column.leafIndex : Math.max(cellSelectionService.lastSelectionItemColIndex, item.column.leafIndex);
760
+ if (preserveSelection) {
761
+ cellSelectionService.lastSelectionItemRowIndex = startRow;
762
+ cellSelectionService.lastSelectionItemColIndex = startColumn;
763
+ this.currentSelection = cellSelectionService.currentSelection;
764
+ }
765
+ const ev = cellSelectionService.selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex, preserveSelection, this.currentSelection);
740
766
  cellSelectionService.changes.emit(ev);
741
767
  }
742
- handleMultipleArrowRowSelection(item) {
768
+ handleMultipleArrowRowSelection(item, preserveSelection, startRow) {
743
769
  const rowSelectionService = this.ctx.grid.selectionService;
744
- const startRowIndex = Math.min(rowSelectionService.lastSelectionStartIndex, item.index);
745
- const endRowIndex = Math.max(rowSelectionService.lastSelectionStartIndex, item.index);
746
- const ev = rowSelectionService.selectRange(startRowIndex, endRowIndex);
770
+ const startRowIndex = preserveSelection ? startRow : Math.min(rowSelectionService.lastSelectionStartIndex, item.index);
771
+ const endRowIndex = preserveSelection ? item.index : Math.max(rowSelectionService.lastSelectionStartIndex, item.index);
772
+ if (preserveSelection) {
773
+ rowSelectionService.lastSelectionStartIndex = startRow;
774
+ this.currentSelection = rowSelectionService.currentSelection;
775
+ }
776
+ const ev = rowSelectionService.selectRange(startRowIndex, endRowIndex, preserveSelection, this.currentSelection);
747
777
  rowSelectionService.changes.emit(ev);
748
778
  }
749
779
  calculateRowspanOffset(direction, cellRowspan) {
@@ -10,7 +10,7 @@ export const packageMetadata = {
10
10
  productName: 'Kendo UI for Angular',
11
11
  productCode: 'KENDOUIANGULAR',
12
12
  productCodes: ['KENDOUIANGULAR'],
13
- publishDate: 1743598444,
14
- version: '18.4.1-develop.2',
13
+ publishDate: 1743748634,
14
+ version: '18.5.0-develop.1',
15
15
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
16
16
  };
@@ -3,7 +3,7 @@
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  import { Injectable, EventEmitter } from '@angular/core';
6
- import { iterator } from '../utils';
6
+ import { iterator, isMultipleRangesEnabled } from '../utils';
7
7
  import { isPresent } from '../utils';
8
8
  import { DomEventsService } from '../common/dom-events.service';
9
9
  import { LocalDataChangesService } from '../editing/local-data-changes.service';
@@ -116,7 +116,12 @@ export class CellSelectionService {
116
116
  const startColIndex = Math.min(this.lastSelectionItemColIndex, item.column.leafIndex);
117
117
  const endRowIndex = Math.max(this.lastSelectionItemRowIndex, item.index);
118
118
  const endColIndex = Math.max(this.lastSelectionItemColIndex, item.column.leafIndex);
119
- ev = this.selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex);
119
+ const preserveCurrentSelection = isMultipleRangesEnabled(this.settings);
120
+ ev = this.selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex, preserveCurrentSelection);
121
+ if (preserveCurrentSelection) {
122
+ this.lastSelectionItemRowIndex = item.index;
123
+ this.lastSelectionItemColIndex = item.column.leafIndex;
124
+ }
120
125
  }
121
126
  }
122
127
  if (!isPresent(ev)) {
@@ -207,7 +212,7 @@ export class CellSelectionService {
207
212
  }
208
213
  }
209
214
  }
210
- selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex) {
215
+ selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex, preserveSelection = false, existingSelections = []) {
211
216
  const selectedCells = [];
212
217
  const deselectedCells = [];
213
218
  const selectionStartRow = Math.min(startRowIndex, endRowIndex);
@@ -231,7 +236,10 @@ export class CellSelectionService {
231
236
  const isInColRange = selectionStartCol <= col.leafIndex && col.leafIndex <= selectionEndCol;
232
237
  const isInSelectionRect = isInRowRange && isInColRange;
233
238
  if (!isInSelectionRect && selected) {
234
- deselectedCells.push(item);
239
+ const deselectCell = !(preserveSelection || existingSelections.find((value) => value && value.itemKey === item.itemKey && value.columnKey === item.columnKey));
240
+ if (deselectCell) {
241
+ deselectedCells.push(item);
242
+ }
235
243
  }
236
244
  if (isInSelectionRect && !selected && !this.nonSelectableRows.has(idx)) {
237
245
  selectedCells.push(item);
@@ -9,6 +9,7 @@ import { SelectionService } from './selection.service';
9
9
  import { CellSelectionService } from './cell-selection.service';
10
10
  import { take, delay } from 'rxjs/operators';
11
11
  import { merge } from 'rxjs';
12
+ import { isMultipleRangesEnabled } from '../utils';
12
13
  import * as i0 from "@angular/core";
13
14
  import * as i1 from "@progress/kendo-angular-common";
14
15
  import * as i2 from "./selection.service";
@@ -115,13 +116,17 @@ export class GridMarqueeDirective {
115
116
  }
116
117
  endSelection(args) {
117
118
  if (args.type === 'mouseup' || args.type === 'touchend') {
119
+ const modifier = args.originalEvent.ctrlKey || args.originalEvent.metaKey;
120
+ const preserveCurrentSelection = modifier &&
121
+ (isMultipleRangesEnabled(this.selection.settings) ||
122
+ isMultipleRangesEnabled(this.cellSelection.settings));
118
123
  if (this.cellSelection.active) {
119
124
  this.cellSelection.dragging = true;
120
- this.cellSelection.changes.emit(this.cellSelection.selectRange(this.pressTarget.rowIndex, this.pressTarget.column.leafIndex, args.rowIndex, args.column.leafIndex));
125
+ this.cellSelection.changes.emit(this.cellSelection.selectRange(this.pressTarget.rowIndex, this.pressTarget.column.leafIndex, args.rowIndex, args.column.leafIndex, preserveCurrentSelection));
121
126
  }
122
127
  else if (this.selection.active) {
123
128
  this.selection.dragging = true;
124
- this.selection.changes.emit(this.selection.selectRange(this.pressTarget.rowIndex, args.rowIndex));
129
+ this.selection.changes.emit(this.selection.selectRange(this.pressTarget.rowIndex, args.rowIndex, preserveCurrentSelection));
125
130
  }
126
131
  }
127
132
  this.clean();
@@ -4,7 +4,7 @@
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  import { Injectable, EventEmitter } from '@angular/core';
6
6
  import { iterator } from '../utils';
7
- import { isPresent } from '../utils';
7
+ import { isPresent, isMultipleRangesEnabled } from '../utils';
8
8
  import { DomEventsService } from '../common/dom-events.service';
9
9
  import { LocalDataChangesService } from '../editing/local-data-changes.service';
10
10
  import { NavigationService } from '../navigation/navigation.service';
@@ -121,7 +121,8 @@ export class SelectionService {
121
121
  ev = this.toggle(item);
122
122
  }
123
123
  else if (event.shiftKey) {
124
- ev = this.addAllTo(item, ctrlKey);
124
+ const preserveCurrentSelection = isMultipleRangesEnabled(this.settings);
125
+ ev = this.addAllTo(item, ctrlKey, preserveCurrentSelection);
125
126
  }
126
127
  }
127
128
  if (!isPresent(ev)) {
@@ -228,7 +229,7 @@ export class SelectionService {
228
229
  item = iterator.next();
229
230
  }
230
231
  }
231
- addAllTo(item, ctrlKey) {
232
+ addAllTo(item, ctrlKey, preserveSelection = false) {
232
233
  const selectedRows = [];
233
234
  const deselectedRows = [];
234
235
  const start = Math.min(this.lastSelectionStartIndex, item.index);
@@ -239,7 +240,7 @@ export class SelectionService {
239
240
  if (next.value && next.value.type === "data") {
240
241
  const idx = next.value.index;
241
242
  const rowArgs = { dataItem: next.value.data, index: idx };
242
- if ((idx < start || idx > end) && this.isSelected(idx) && !ctrlKey) {
243
+ if ((idx < start || idx > end) && this.isSelected(idx) && !ctrlKey && !preserveSelection) {
243
244
  deselectedRows.push(rowArgs);
244
245
  }
245
246
  if ((idx >= start && idx <= end) && !this.isSelected(idx) && !this.nonSelectableRows.has(idx)) {
@@ -296,7 +297,7 @@ export class SelectionService {
296
297
  }
297
298
  this.changes.emit(ev);
298
299
  }
299
- selectRange(startIndex, endIndex) {
300
+ selectRange(startIndex, endIndex, preserveSelection, existingSelections = []) {
300
301
  const selectedRows = [];
301
302
  const deselectedRows = [];
302
303
  const start = Math.min(startIndex, endIndex);
@@ -308,7 +309,10 @@ export class SelectionService {
308
309
  const idx = next.value.index;
309
310
  const rowArgs = { dataItem: next.value.data, index: idx };
310
311
  if ((idx < start || idx > end) && this.isSelected(idx)) {
311
- deselectedRows.push(rowArgs);
312
+ const deselectRow = !(preserveSelection || existingSelections.find((value) => value && value.dataItem === rowArgs.dataItem && value.index === rowArgs.index));
313
+ if (deselectRow) {
314
+ deselectedRows.push(rowArgs);
315
+ }
312
316
  }
313
317
  if ((idx >= start && idx <= end) && !this.isSelected(idx) && !this.nonSelectableRows.has(idx)) {
314
318
  selectedRows.push(rowArgs);
package/esm2022/utils.mjs CHANGED
@@ -190,3 +190,12 @@ const findRowSpan = (data, index, field) => {
190
190
  }
191
191
  return rowspan;
192
192
  };
193
+ /**
194
+ * @hidden
195
+ * Determines whether selection of multiple ranges is enabled in the selectable settings.
196
+ */
197
+ export const isMultipleRangesEnabled = (selectableSettings) => {
198
+ return selectableSettings &&
199
+ typeof selectableSettings === 'object' &&
200
+ selectableSettings.selectable.multipleRanges;
201
+ };
@@ -506,6 +506,15 @@ const findRowSpan = (data, index, field) => {
506
506
  }
507
507
  return rowspan;
508
508
  };
509
+ /**
510
+ * @hidden
511
+ * Determines whether selection of multiple ranges is enabled in the selectable settings.
512
+ */
513
+ const isMultipleRangesEnabled = (selectableSettings) => {
514
+ return selectableSettings &&
515
+ typeof selectableSettings === 'object' &&
516
+ selectableSettings.selectable.multipleRanges;
517
+ };
509
518
 
510
519
  /**
511
520
  * @hidden
@@ -1416,6 +1425,7 @@ class DomEventsService {
1416
1425
  cellMouseup = new EventEmitter();
1417
1426
  click = new EventEmitter();
1418
1427
  keydown = new EventEmitter();
1428
+ shiftKeyup = new EventEmitter();
1419
1429
  focus = new EventEmitter();
1420
1430
  focusIn = new EventEmitter();
1421
1431
  focusOut = new EventEmitter();
@@ -3452,6 +3462,8 @@ class NavigationService {
3452
3462
  tableIsNavigable = false;
3453
3463
  toolbarIsNavigable = false;
3454
3464
  lastCellRowIndex;
3465
+ isShiftPressed = false;
3466
+ currentSelection = [];
3455
3467
  get activeDataRow() {
3456
3468
  return Math.max(0, this.activeRowIndex - this.meta.headerRows);
3457
3469
  }
@@ -3496,6 +3508,10 @@ class NavigationService {
3496
3508
  .subscribe(() => this.cursor.reset(0, 0)));
3497
3509
  this.subs.add(this.domEvents.keydown
3498
3510
  .subscribe(args => this.onKeydown(args)));
3511
+ this.subs.add(this.domEvents.shiftKeyup
3512
+ .subscribe(() => {
3513
+ this.isShiftPressed = false;
3514
+ }));
3499
3515
  this.subs.add(this.domEvents.keydown.pipe(filter(args => args.keyCode === Keys.Tab && this.mode === 2 /* NavigationMode.Content */), switchMapTo(this.domEvents.focusOut.pipe(takeUntil(
3500
3516
  // Timeout if focusOut doesn't fire very soon
3501
3517
  interval(0).pipe(take(1))))))
@@ -3733,12 +3749,23 @@ class NavigationService {
3733
3749
  let step = modifier ? 5 : 1;
3734
3750
  const rowspan = +args.target?.getAttribute('rowspan');
3735
3751
  let rowspanOffset = 0;
3752
+ let startNewSelection = false;
3753
+ const allowMultipleRanges = (this.ctx.grid.selectionService.active && this.ctx.grid.selectableSettings?.multipleRanges) ||
3754
+ (this.ctx.grid.cellSelectionService.active && this.ctx.grid.cellSelectionService?.options?.multipleRanges);
3755
+ if (!allowMultipleRanges) {
3756
+ this.currentSelection = [];
3757
+ }
3736
3758
  if (!this.onCellKeydown(args)) {
3737
3759
  return;
3738
3760
  }
3739
3761
  const row = this.cursor.row;
3740
3762
  const dir = args.keyCode === Keys.ArrowDown ? 'Down' : 'Up';
3741
3763
  const right = args.keyCode === Keys.ArrowRight;
3764
+ const isArrowKey = args.code === 'ArrowDown' || args.code === 'ArrowUp' || args.code === 'ArrowLeft' || args.code === 'ArrowRight';
3765
+ if (!this.isShiftPressed && args.shiftKey && isArrowKey) {
3766
+ startNewSelection = true;
3767
+ this.isShiftPressed = true;
3768
+ }
3742
3769
  switch (args.keyCode) {
3743
3770
  case Keys.ArrowDown:
3744
3771
  case Keys.ArrowUp:
@@ -3751,9 +3778,10 @@ class NavigationService {
3751
3778
  return;
3752
3779
  }
3753
3780
  preventDefault = this.cursor[`move${dir}`](step);
3781
+ const preserveCurrentSelection = startNewSelection && allowMultipleRanges;
3754
3782
  if (this.activeRow?.dataItem) {
3755
3783
  const sign = dir === 'Down' ? 1 : -1;
3756
- this.handleVerticalArrowSelection(sign * step);
3784
+ this.handleVerticalArrowSelection(sign * step, preserveCurrentSelection);
3757
3785
  }
3758
3786
  }
3759
3787
  else {
@@ -3772,7 +3800,8 @@ class NavigationService {
3772
3800
  return;
3773
3801
  }
3774
3802
  preventDefault = this[`moveCursor${right ? 'Fwd' : 'Bwd'}`]();
3775
- this.handleHorizontalArrowSelection(args);
3803
+ const preserveCurrentSelection = startNewSelection && allowMultipleRanges;
3804
+ this.handleHorizontalArrowSelection(args, preserveCurrentSelection);
3776
3805
  }
3777
3806
  else {
3778
3807
  preventDefault = this[`moveCursor${right ? 'Fwd' : 'Bwd'}`]();
@@ -3975,7 +4004,7 @@ class NavigationService {
3975
4004
  this.leaveCell();
3976
4005
  this.cursor.reset();
3977
4006
  }
3978
- handleVerticalArrowSelection(args) {
4007
+ handleVerticalArrowSelection(args, preserveSelection) {
3979
4008
  const cellSelectionEnabled = this.ctx.grid.cellSelectionService.active;
3980
4009
  const rowSelectionEnabled = this.ctx.grid.selectionService.active && !this.ctx.grid.selectableSettings.checkboxOnly;
3981
4010
  if (cellSelectionEnabled || rowSelectionEnabled) {
@@ -3985,14 +4014,15 @@ class NavigationService {
3985
4014
  const dataItem = selectionService.settings.view.at(rowIdx);
3986
4015
  const item = { index: this.activeRow.dataRowIndex, data: dataItem, column: this.ctx.grid.columnsContainer.leafColumnsToRender[colIdx] };
3987
4016
  if (selectionService.options.mode === 'multiple') {
3988
- cellSelectionEnabled ? this.handleMultipleArrowCellSelection(item) : this.handleMultipleArrowRowSelection(item);
4017
+ const startRowIndex = this.activeRow.dataRowIndex - args;
4018
+ cellSelectionEnabled ? this.handleMultipleArrowCellSelection(item, preserveSelection, startRowIndex, colIdx) : this.handleMultipleArrowRowSelection(item, preserveSelection, startRowIndex);
3989
4019
  }
3990
4020
  else {
3991
4021
  selectionService.handleClick(item, args);
3992
4022
  }
3993
4023
  }
3994
4024
  }
3995
- handleHorizontalArrowSelection(args) {
4025
+ handleHorizontalArrowSelection(args, preserveSelection) {
3996
4026
  const cellSelectionEnabled = this.ctx.grid.cellSelectionService.active;
3997
4027
  if (cellSelectionEnabled) {
3998
4028
  const selectionService = this.ctx.grid[cellSelectionEnabled ? 'cellSelectionService' : 'selectionService'];
@@ -4004,27 +4034,37 @@ class NavigationService {
4004
4034
  return;
4005
4035
  }
4006
4036
  if (selectionService.options.mode === 'multiple') {
4007
- this.handleMultipleArrowCellSelection(item);
4037
+ const startColumnIndex = args.key === 'ArrowRight' ? colIdx - 1 : colIdx + 1;
4038
+ this.handleMultipleArrowCellSelection(item, preserveSelection, row.dataRowIndex, startColumnIndex);
4008
4039
  }
4009
4040
  else {
4010
4041
  selectionService.handleClick(item, args);
4011
4042
  }
4012
4043
  }
4013
4044
  }
4014
- handleMultipleArrowCellSelection(item) {
4045
+ handleMultipleArrowCellSelection(item, preserveSelection, startRow, startColumn) {
4015
4046
  const cellSelectionService = this.ctx.grid.cellSelectionService;
4016
- const startRowIndex = Math.min(cellSelectionService.lastSelectionItemRowIndex, item.index);
4017
- const startColIndex = Math.min(cellSelectionService.lastSelectionItemColIndex, item.column.leafIndex);
4018
- const endRowIndex = Math.max(cellSelectionService.lastSelectionItemRowIndex, item.index);
4019
- const endColIndex = Math.max(cellSelectionService.lastSelectionItemColIndex, item.column.leafIndex);
4020
- const ev = cellSelectionService.selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex);
4047
+ const startRowIndex = preserveSelection ? startRow : Math.min(cellSelectionService.lastSelectionItemRowIndex, item.index);
4048
+ const startColIndex = preserveSelection ? startColumn : Math.min(cellSelectionService.lastSelectionItemColIndex, item.column.leafIndex);
4049
+ const endRowIndex = preserveSelection ? item.index : Math.max(cellSelectionService.lastSelectionItemRowIndex, item.index);
4050
+ const endColIndex = preserveSelection ? item.column.leafIndex : Math.max(cellSelectionService.lastSelectionItemColIndex, item.column.leafIndex);
4051
+ if (preserveSelection) {
4052
+ cellSelectionService.lastSelectionItemRowIndex = startRow;
4053
+ cellSelectionService.lastSelectionItemColIndex = startColumn;
4054
+ this.currentSelection = cellSelectionService.currentSelection;
4055
+ }
4056
+ const ev = cellSelectionService.selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex, preserveSelection, this.currentSelection);
4021
4057
  cellSelectionService.changes.emit(ev);
4022
4058
  }
4023
- handleMultipleArrowRowSelection(item) {
4059
+ handleMultipleArrowRowSelection(item, preserveSelection, startRow) {
4024
4060
  const rowSelectionService = this.ctx.grid.selectionService;
4025
- const startRowIndex = Math.min(rowSelectionService.lastSelectionStartIndex, item.index);
4026
- const endRowIndex = Math.max(rowSelectionService.lastSelectionStartIndex, item.index);
4027
- const ev = rowSelectionService.selectRange(startRowIndex, endRowIndex);
4061
+ const startRowIndex = preserveSelection ? startRow : Math.min(rowSelectionService.lastSelectionStartIndex, item.index);
4062
+ const endRowIndex = preserveSelection ? item.index : Math.max(rowSelectionService.lastSelectionStartIndex, item.index);
4063
+ if (preserveSelection) {
4064
+ rowSelectionService.lastSelectionStartIndex = startRow;
4065
+ this.currentSelection = rowSelectionService.currentSelection;
4066
+ }
4067
+ const ev = rowSelectionService.selectRange(startRowIndex, endRowIndex, preserveSelection, this.currentSelection);
4028
4068
  rowSelectionService.changes.emit(ev);
4029
4069
  }
4030
4070
  calculateRowspanOffset(direction, cellRowspan) {
@@ -15458,7 +15498,8 @@ class SelectionService {
15458
15498
  ev = this.toggle(item);
15459
15499
  }
15460
15500
  else if (event.shiftKey) {
15461
- ev = this.addAllTo(item, ctrlKey);
15501
+ const preserveCurrentSelection = isMultipleRangesEnabled(this.settings);
15502
+ ev = this.addAllTo(item, ctrlKey, preserveCurrentSelection);
15462
15503
  }
15463
15504
  }
15464
15505
  if (!isPresent(ev)) {
@@ -15565,7 +15606,7 @@ class SelectionService {
15565
15606
  item = iterator.next();
15566
15607
  }
15567
15608
  }
15568
- addAllTo(item, ctrlKey) {
15609
+ addAllTo(item, ctrlKey, preserveSelection = false) {
15569
15610
  const selectedRows = [];
15570
15611
  const deselectedRows = [];
15571
15612
  const start = Math.min(this.lastSelectionStartIndex, item.index);
@@ -15576,7 +15617,7 @@ class SelectionService {
15576
15617
  if (next.value && next.value.type === "data") {
15577
15618
  const idx = next.value.index;
15578
15619
  const rowArgs = { dataItem: next.value.data, index: idx };
15579
- if ((idx < start || idx > end) && this.isSelected(idx) && !ctrlKey) {
15620
+ if ((idx < start || idx > end) && this.isSelected(idx) && !ctrlKey && !preserveSelection) {
15580
15621
  deselectedRows.push(rowArgs);
15581
15622
  }
15582
15623
  if ((idx >= start && idx <= end) && !this.isSelected(idx) && !this.nonSelectableRows.has(idx)) {
@@ -15633,7 +15674,7 @@ class SelectionService {
15633
15674
  }
15634
15675
  this.changes.emit(ev);
15635
15676
  }
15636
- selectRange(startIndex, endIndex) {
15677
+ selectRange(startIndex, endIndex, preserveSelection, existingSelections = []) {
15637
15678
  const selectedRows = [];
15638
15679
  const deselectedRows = [];
15639
15680
  const start = Math.min(startIndex, endIndex);
@@ -15645,7 +15686,10 @@ class SelectionService {
15645
15686
  const idx = next.value.index;
15646
15687
  const rowArgs = { dataItem: next.value.data, index: idx };
15647
15688
  if ((idx < start || idx > end) && this.isSelected(idx)) {
15648
- deselectedRows.push(rowArgs);
15689
+ const deselectRow = !(preserveSelection || existingSelections.find((value) => value && value.dataItem === rowArgs.dataItem && value.index === rowArgs.index));
15690
+ if (deselectRow) {
15691
+ deselectedRows.push(rowArgs);
15692
+ }
15649
15693
  }
15650
15694
  if ((idx >= start && idx <= end) && !this.isSelected(idx) && !this.nonSelectableRows.has(idx)) {
15651
15695
  selectedRows.push(rowArgs);
@@ -15870,7 +15914,12 @@ class CellSelectionService {
15870
15914
  const startColIndex = Math.min(this.lastSelectionItemColIndex, item.column.leafIndex);
15871
15915
  const endRowIndex = Math.max(this.lastSelectionItemRowIndex, item.index);
15872
15916
  const endColIndex = Math.max(this.lastSelectionItemColIndex, item.column.leafIndex);
15873
- ev = this.selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex);
15917
+ const preserveCurrentSelection = isMultipleRangesEnabled(this.settings);
15918
+ ev = this.selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex, preserveCurrentSelection);
15919
+ if (preserveCurrentSelection) {
15920
+ this.lastSelectionItemRowIndex = item.index;
15921
+ this.lastSelectionItemColIndex = item.column.leafIndex;
15922
+ }
15874
15923
  }
15875
15924
  }
15876
15925
  if (!isPresent(ev)) {
@@ -15961,7 +16010,7 @@ class CellSelectionService {
15961
16010
  }
15962
16011
  }
15963
16012
  }
15964
- selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex) {
16013
+ selectRange(startRowIndex, startColIndex, endRowIndex, endColIndex, preserveSelection = false, existingSelections = []) {
15965
16014
  const selectedCells = [];
15966
16015
  const deselectedCells = [];
15967
16016
  const selectionStartRow = Math.min(startRowIndex, endRowIndex);
@@ -15985,7 +16034,10 @@ class CellSelectionService {
15985
16034
  const isInColRange = selectionStartCol <= col.leafIndex && col.leafIndex <= selectionEndCol;
15986
16035
  const isInSelectionRect = isInRowRange && isInColRange;
15987
16036
  if (!isInSelectionRect && selected) {
15988
- deselectedCells.push(item);
16037
+ const deselectCell = !(preserveSelection || existingSelections.find((value) => value && value.itemKey === item.itemKey && value.columnKey === item.columnKey));
16038
+ if (deselectCell) {
16039
+ deselectedCells.push(item);
16040
+ }
15989
16041
  }
15990
16042
  if (isInSelectionRect && !selected && !this.nonSelectableRows.has(idx)) {
15991
16043
  selectedCells.push(item);
@@ -19761,8 +19813,8 @@ const packageMetadata = {
19761
19813
  productName: 'Kendo UI for Angular',
19762
19814
  productCode: 'KENDOUIANGULAR',
19763
19815
  productCodes: ['KENDOUIANGULAR'],
19764
- publishDate: 1743598444,
19765
- version: '18.4.1-develop.2',
19816
+ publishDate: 1743748634,
19817
+ version: '18.5.0-develop.1',
19766
19818
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
19767
19819
  };
19768
19820
 
@@ -21373,13 +21425,17 @@ class GridMarqueeDirective {
21373
21425
  }
21374
21426
  endSelection(args) {
21375
21427
  if (args.type === 'mouseup' || args.type === 'touchend') {
21428
+ const modifier = args.originalEvent.ctrlKey || args.originalEvent.metaKey;
21429
+ const preserveCurrentSelection = modifier &&
21430
+ (isMultipleRangesEnabled(this.selection.settings) ||
21431
+ isMultipleRangesEnabled(this.cellSelection.settings));
21376
21432
  if (this.cellSelection.active) {
21377
21433
  this.cellSelection.dragging = true;
21378
- this.cellSelection.changes.emit(this.cellSelection.selectRange(this.pressTarget.rowIndex, this.pressTarget.column.leafIndex, args.rowIndex, args.column.leafIndex));
21434
+ this.cellSelection.changes.emit(this.cellSelection.selectRange(this.pressTarget.rowIndex, this.pressTarget.column.leafIndex, args.rowIndex, args.column.leafIndex, preserveCurrentSelection));
21379
21435
  }
21380
21436
  else if (this.selection.active) {
21381
21437
  this.selection.dragging = true;
21382
- this.selection.changes.emit(this.selection.selectRange(this.pressTarget.rowIndex, args.rowIndex));
21438
+ this.selection.changes.emit(this.selection.selectRange(this.pressTarget.rowIndex, args.rowIndex, preserveCurrentSelection));
21383
21439
  }
21384
21440
  }
21385
21441
  this.clean();
@@ -25330,6 +25386,11 @@ class GridComponent {
25330
25386
  const keydownSubscription = this.renderer.listen(wrapper, 'keydown', (args) => {
25331
25387
  this.domEvents.keydown.emit(args);
25332
25388
  });
25389
+ const shiftKeyupSubscription = this.renderer.listen(wrapper, 'keyup', (args) => {
25390
+ if (args.key === 'Shift') {
25391
+ this.domEvents.shiftKeyup.emit(args);
25392
+ }
25393
+ });
25333
25394
  // focusIn and focusOut are relative to the element with ARIA role "grid"
25334
25395
  let focused = false;
25335
25396
  const focusInSubscription = this.renderer.listen(ariaRoot, 'focusin', (args) => {
@@ -25344,6 +25405,7 @@ class GridComponent {
25344
25405
  const outside = !closest(next, (node) => node === ariaRoot);
25345
25406
  if (outside) {
25346
25407
  this.domEvents.focusOut.emit(args);
25408
+ this.domEvents.shiftKeyup.emit(args);
25347
25409
  focused = false;
25348
25410
  }
25349
25411
  });
@@ -25354,6 +25416,7 @@ class GridComponent {
25354
25416
  windowBlurSubscription();
25355
25417
  clickSubscription();
25356
25418
  keydownSubscription();
25419
+ shiftKeyupSubscription();
25357
25420
  focusInSubscription();
25358
25421
  focusOutSubscription();
25359
25422
  };
@@ -75,6 +75,8 @@ export declare class NavigationService implements OnDestroy {
75
75
  private tableIsNavigable;
76
76
  private toolbarIsNavigable;
77
77
  private lastCellRowIndex;
78
+ private isShiftPressed;
79
+ private currentSelection;
78
80
  private get activeDataRow();
79
81
  constructor(zone: NgZone, domEvents: DomEventsService, pagerContextService: PagerContextService, scrollRequestService: ScrollRequestService, groupsService: GroupsService, detailsService: DetailsService, focusRoot: FocusRoot, editService: EditService, cd: ChangeDetectorRef, ctx: ContextService, resizeService: ColumnResizingService, focusableParent: FocusableDirective);
80
82
  init(meta: NavigationMetadata, navigableOptions: GridNavigableSection[]): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@progress/kendo-angular-grid",
3
- "version": "18.4.1-develop.2",
3
+ "version": "18.5.0-develop.1",
4
4
  "description": "Kendo UI Grid for Angular - high performance data grid with paging, filtering, virtualization, CRUD, and more.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "Progress",
@@ -26,7 +26,7 @@
26
26
  "package": {
27
27
  "productName": "Kendo UI for Angular",
28
28
  "productCode": "KENDOUIANGULAR",
29
- "publishDate": 1743598444,
29
+ "publishDate": 1743748634,
30
30
  "licensingDocsUrl": "https://www.telerik.com/kendo-angular-ui/my-license/"
31
31
  }
32
32
  },
@@ -39,27 +39,27 @@
39
39
  "@progress/kendo-data-query": "^1.0.0",
40
40
  "@progress/kendo-drawing": "^1.21.0",
41
41
  "@progress/kendo-licensing": "^1.5.0",
42
- "@progress/kendo-angular-buttons": "18.4.1-develop.2",
43
- "@progress/kendo-angular-common": "18.4.1-develop.2",
44
- "@progress/kendo-angular-dateinputs": "18.4.1-develop.2",
45
- "@progress/kendo-angular-layout": "18.4.1-develop.2",
46
- "@progress/kendo-angular-dropdowns": "18.4.1-develop.2",
47
- "@progress/kendo-angular-excel-export": "18.4.1-develop.2",
48
- "@progress/kendo-angular-icons": "18.4.1-develop.2",
49
- "@progress/kendo-angular-inputs": "18.4.1-develop.2",
50
- "@progress/kendo-angular-intl": "18.4.1-develop.2",
51
- "@progress/kendo-angular-l10n": "18.4.1-develop.2",
52
- "@progress/kendo-angular-label": "18.4.1-develop.2",
53
- "@progress/kendo-angular-pager": "18.4.1-develop.2",
54
- "@progress/kendo-angular-pdf-export": "18.4.1-develop.2",
55
- "@progress/kendo-angular-popup": "18.4.1-develop.2",
56
- "@progress/kendo-angular-toolbar": "18.4.1-develop.2",
57
- "@progress/kendo-angular-utils": "18.4.1-develop.2",
42
+ "@progress/kendo-angular-buttons": "18.5.0-develop.1",
43
+ "@progress/kendo-angular-common": "18.5.0-develop.1",
44
+ "@progress/kendo-angular-dateinputs": "18.5.0-develop.1",
45
+ "@progress/kendo-angular-layout": "18.5.0-develop.1",
46
+ "@progress/kendo-angular-dropdowns": "18.5.0-develop.1",
47
+ "@progress/kendo-angular-excel-export": "18.5.0-develop.1",
48
+ "@progress/kendo-angular-icons": "18.5.0-develop.1",
49
+ "@progress/kendo-angular-inputs": "18.5.0-develop.1",
50
+ "@progress/kendo-angular-intl": "18.5.0-develop.1",
51
+ "@progress/kendo-angular-l10n": "18.5.0-develop.1",
52
+ "@progress/kendo-angular-label": "18.5.0-develop.1",
53
+ "@progress/kendo-angular-pager": "18.5.0-develop.1",
54
+ "@progress/kendo-angular-pdf-export": "18.5.0-develop.1",
55
+ "@progress/kendo-angular-popup": "18.5.0-develop.1",
56
+ "@progress/kendo-angular-toolbar": "18.5.0-develop.1",
57
+ "@progress/kendo-angular-utils": "18.5.0-develop.1",
58
58
  "rxjs": "^6.5.3 || ^7.0.0"
59
59
  },
60
60
  "dependencies": {
61
61
  "tslib": "^2.3.1",
62
- "@progress/kendo-angular-schematics": "18.4.1-develop.2",
62
+ "@progress/kendo-angular-schematics": "18.5.0-develop.1",
63
63
  "@progress/kendo-common": "^1.0.1",
64
64
  "@progress/kendo-file-saver": "^1.0.0"
65
65
  },
@@ -4,14 +4,14 @@ const schematics_1 = require("@angular-devkit/schematics");
4
4
  function default_1(options) {
5
5
  const finalOptions = Object.assign(Object.assign({}, options), { mainNgModule: 'GridModule', package: 'grid', peerDependencies: {
6
6
  // peer deps of the dropdowns
7
- '@progress/kendo-angular-treeview': '18.4.1-develop.2',
8
- '@progress/kendo-angular-navigation': '18.4.1-develop.2',
7
+ '@progress/kendo-angular-treeview': '18.5.0-develop.1',
8
+ '@progress/kendo-angular-navigation': '18.5.0-develop.1',
9
9
  // peer dependency of kendo-angular-inputs
10
- '@progress/kendo-angular-dialog': '18.4.1-develop.2',
10
+ '@progress/kendo-angular-dialog': '18.5.0-develop.1',
11
11
  // peer dependency of kendo-angular-icons
12
12
  '@progress/kendo-svg-icons': '^4.0.0',
13
13
  // peer dependency of kendo-angular-layout
14
- '@progress/kendo-angular-progressbar': '18.4.1-develop.2'
14
+ '@progress/kendo-angular-progressbar': '18.5.0-develop.1'
15
15
  } });
16
16
  return (0, schematics_1.externalSchematic)('@progress/kendo-angular-schematics', 'ng-add', finalOptions);
17
17
  }
@@ -60,7 +60,7 @@ export declare class CellSelectionService implements OnDestroy {
60
60
  toggle(item: any): any;
61
61
  select(item: any): any;
62
62
  deselect(removedItem: any): void;
63
- selectRange(startRowIndex: number, startColIndex: number, endRowIndex: number, endColIndex: number): any;
63
+ selectRange(startRowIndex: number, startColIndex: number, endRowIndex: number, endColIndex: number, preserveSelection?: boolean, existingSelections?: any[]): any;
64
64
  get options(): SelectableSettings;
65
65
  ngOnDestroy(): void;
66
66
  addSubscriptions(): void;
@@ -59,9 +59,9 @@ export declare class SelectionService implements OnDestroy {
59
59
  toggleByIndex(index: number): any;
60
60
  select(item: any): any;
61
61
  deselect(removedItem: any): void;
62
- addAllTo(item: any, ctrlKey: boolean): any;
62
+ addAllTo(item: any, ctrlKey: boolean, preserveSelection?: boolean): any;
63
63
  updateAll(selectAllChecked: boolean): void;
64
- selectRange(startIndex: number, endIndex: number): any;
64
+ selectRange(startIndex: number, endIndex: number, preserveSelection: boolean, existingSelections?: any[]): any;
65
65
  get selectAllState(): any;
66
66
  get selected(): number[];
67
67
  get options(): SelectableSettings;
@@ -111,6 +111,11 @@ export interface SelectableSettings {
111
111
  *
112
112
  */
113
113
  metaKeyMultiSelect?: boolean;
114
+ /**
115
+ * Determines whether the existing selection is preserved when a new range selection is performed.
116
+ *
117
+ */
118
+ multipleRanges?: boolean;
114
119
  }
115
120
  /**
116
121
  * Represents the available selection modes. [See example](slug:grid_row_selection).
package/utils.d.ts CHANGED
@@ -105,3 +105,8 @@ export declare const roundDown: (value: number) => number;
105
105
  * @hidden
106
106
  */
107
107
  export declare const defaultCellRowSpan: (row: RowArgs, column: ColumnBase, data: any[]) => number;
108
+ /**
109
+ * @hidden
110
+ * Determines whether selection of multiple ranges is enabled in the selectable settings.
111
+ */
112
+ export declare const isMultipleRangesEnabled: (selectableSettings: any) => boolean;