@progress/kendo-angular-sortable 19.0.0-develop.8 → 19.0.0

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.
@@ -10,7 +10,7 @@ export const packageMetadata = {
10
10
  productName: 'Kendo UI for Angular',
11
11
  productCode: 'KENDOUIANGULAR',
12
12
  productCodes: ['KENDOUIANGULAR'],
13
- publishDate: 1746081442,
14
- version: '19.0.0-develop.8',
13
+ publishDate: 1748362656,
14
+ version: '19.0.0',
15
15
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
16
16
  };
@@ -5,7 +5,7 @@
5
5
  /* eslint-disable @typescript-eslint/no-explicit-any */
6
6
  import { Component, Input, Output, QueryList, ContentChildren, ViewChild, ViewChildren, TemplateRef, ElementRef, EventEmitter, HostBinding, NgZone, ChangeDetectorRef, forwardRef, Renderer2 } from '@angular/core';
7
7
  import { Subject, merge } from 'rxjs';
8
- import { isDocumentAvailable, isChanged, Keys } from '@progress/kendo-angular-common';
8
+ import { isDocumentAvailable, isChanged, Keys, EventsOutsideAngularDirective } from '@progress/kendo-angular-common';
9
9
  import { getAllFocusableChildren, keepFocusWithinComponent, relativeContextElement } from './util';
10
10
  import { filter, take } from 'rxjs/operators';
11
11
  import { LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n';
@@ -37,10 +37,15 @@ export class SortableComponent {
37
37
  renderer;
38
38
  changeDetector;
39
39
  localization;
40
+ cdr;
40
41
  /**
41
42
  * Specifies the tab index of the Sortable component.
42
43
  */
43
44
  tabIndex = null;
45
+ /**
46
+ * Configures how the Sortable component will track changes in its items collection.
47
+ */
48
+ trackBy = (_, idx) => idx;
44
49
  /**
45
50
  * Sets an array of any data that is used as a data source for the Sortable.
46
51
  */
@@ -56,17 +61,9 @@ export class SortableComponent {
56
61
  }
57
62
  /**
58
63
  * Enables or disables the [keyboard navigation]({% slug keyboard_navigation_sortable %}).
59
- * @default false
60
- */
61
- navigable = false;
62
- /**
63
- * @hidden
64
- *
65
- * A misspelled alias for `navigable`.
64
+ * @default true
66
65
  */
67
- set navigatable(value) {
68
- this.navigable = value;
69
- }
66
+ navigable = true;
70
67
  /**
71
68
  * Enables or disables the built-in animations.
72
69
  * @default false
@@ -299,11 +296,12 @@ export class SortableComponent {
299
296
  }
300
297
  return template;
301
298
  }
302
- constructor(ngZone, renderer, changeDetector, localization, wrapper, sortableService) {
299
+ constructor(ngZone, renderer, changeDetector, localization, wrapper, sortableService, cdr) {
303
300
  this.ngZone = ngZone;
304
301
  this.renderer = renderer;
305
302
  this.changeDetector = changeDetector;
306
303
  this.localization = localization;
304
+ this.cdr = cdr;
307
305
  validatePackage(packageMetadata);
308
306
  this.wrapper = wrapper.nativeElement;
309
307
  this.direction = localization.rtl ? 'rtl' : 'ltr';
@@ -597,9 +595,9 @@ export class SortableComponent {
597
595
  /**
598
596
  * @hidden
599
597
  */
600
- onEscapeHandler() {
598
+ onEscapeHandler(event) {
601
599
  const focusableItems = this.focusableItems[this.prevActiveIndex];
602
- const item = this.itemWrappers.toArray()[this.prevActiveIndex].nativeElement;
600
+ const item = (event?.target).closest('[data-sortable-item]');
603
601
  focusableItems.forEach(focusableItem => {
604
602
  this.renderer.setAttribute(focusableItem, 'tabindex', '-1');
605
603
  });
@@ -609,27 +607,37 @@ export class SortableComponent {
609
607
  /**
610
608
  * @hidden
611
609
  */
612
- keydownHandler(event) {
610
+ keydownHandler = (event) => {
611
+ if (!this.navigable) {
612
+ return;
613
+ }
614
+ this.cdr.markForCheck();
615
+ const targetIsWrapper = this.itemWrappers.toArray().some((item) => item.nativeElement === event.target);
613
616
  const index = this.activeIndex === -1 ? this.prevActiveIndex : this.activeIndex;
614
- const item = this.itemWrappers.toArray()[index].nativeElement;
617
+ const item = this.itemWrappers.toArray()[index]?.nativeElement;
615
618
  const isItemFocused = document.activeElement === item;
616
619
  const hasFocus = this.activeIndex !== -1;
617
620
  const keyCode = event.keyCode;
621
+ if (keyCode === Keys.Tab && !isItemFocused) {
622
+ keepFocusWithinComponent(event, item);
623
+ return;
624
+ }
625
+ if (keyCode === Keys.Escape && this.focusableItems.length > 0 && this.activeIndex === -1) {
626
+ this.onEscapeHandler(event);
627
+ return;
628
+ }
629
+ if (!targetIsWrapper) {
630
+ return;
631
+ }
618
632
  if (this.navigable && hasFocus) {
619
633
  if (keyCode >= Keys.ArrowLeft && keyCode <= Keys.ArrowDown) {
620
- this.onArrowHandler(event, keyCode);
634
+ this.ngZone.run(() => this.onArrowHandler(event, keyCode));
621
635
  }
622
- if (keyCode === Keys.Enter && isItemFocused && this.focusableItems.length > 0) {
636
+ else if (keyCode === Keys.Enter && isItemFocused && this.focusableItems.length > 0) {
623
637
  this.onEnterHandler(item);
624
638
  }
625
639
  }
626
- if (keyCode === Keys.Tab && !isItemFocused) {
627
- keepFocusWithinComponent(event, item);
628
- }
629
- if (keyCode === Keys.Escape && this.focusableItems.length > 0 && this.activeIndex === -1) {
630
- this.onEscapeHandler();
631
- }
632
- }
640
+ };
633
641
  /**
634
642
  * Removes the currently active item from the Data collection that the Sortable uses.
635
643
  */
@@ -857,6 +865,9 @@ export class SortableComponent {
857
865
  .subscribe(({ rtl }) => this.direction = rtl ? 'rtl' : 'ltr');
858
866
  this.dragStartSubscription = this.onDragStartSubject
859
867
  .subscribe((event) => {
868
+ if (!event.target) {
869
+ return;
870
+ }
860
871
  this.sortableService.originDraggable = event.target;
861
872
  this.sortableService.originIndex = event.target.index;
862
873
  this.sortableService.activeDraggable = event.target;
@@ -994,8 +1005,8 @@ export class SortableComponent {
994
1005
  }
995
1006
  }
996
1007
  }
997
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SortableComponent, deps: [{ token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i1.LocalizationService }, { token: i0.ElementRef }, { token: i2.SortableService }], target: i0.ɵɵFactoryTarget.Component });
998
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SortableComponent, isStandalone: true, selector: "kendo-sortable", inputs: { tabIndex: "tabIndex", data: "data", navigable: "navigable", navigatable: "navigatable", animation: "animation", disabledIndexes: "disabledIndexes", zone: "zone", acceptZones: "acceptZones", itemStyle: "itemStyle", emptyItemStyle: "emptyItemStyle", activeItemStyle: "activeItemStyle", disabledItemStyle: "disabledItemStyle", itemClass: "itemClass", activeItemClass: "activeItemClass", emptyItemClass: "emptyItemClass", disabledItemClass: "disabledItemClass", emptyText: "emptyText", activeIndex: "activeIndex" }, outputs: { dragStart: "dragStart", dragEnd: "dragEnd", dragOver: "dragOver", dragLeave: "dragLeave", dataMove: "dataMove", dataAdd: "dataAdd", dataRemove: "dataRemove", navigate: "navigate" }, host: { properties: { "style.touch-action": "this.touchAction", "attr.dir": "this.dir", "attr.role": "this.hostRole" } }, providers: [
1008
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SortableComponent, deps: [{ token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i1.LocalizationService }, { token: i0.ElementRef }, { token: i2.SortableService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1009
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SortableComponent, isStandalone: true, selector: "kendo-sortable", inputs: { tabIndex: "tabIndex", trackBy: "trackBy", data: "data", navigable: "navigable", animation: "animation", disabledIndexes: "disabledIndexes", zone: "zone", acceptZones: "acceptZones", itemStyle: "itemStyle", emptyItemStyle: "emptyItemStyle", activeItemStyle: "activeItemStyle", disabledItemStyle: "disabledItemStyle", itemClass: "itemClass", activeItemClass: "activeItemClass", emptyItemClass: "emptyItemClass", disabledItemClass: "disabledItemClass", emptyText: "emptyText", activeIndex: "activeIndex" }, outputs: { dragStart: "dragStart", dragEnd: "dragEnd", dragOver: "dragOver", dragLeave: "dragLeave", dataMove: "dataMove", dataAdd: "dataAdd", dataRemove: "dataRemove", navigate: "navigate" }, host: { properties: { "style.touch-action": "this.touchAction", "attr.dir": "this.dir", "attr.role": "this.hostRole" } }, providers: [
999
1010
  LocalizationService,
1000
1011
  {
1001
1012
  provide: L10N_PREFIX,
@@ -1006,7 +1017,7 @@ export class SortableComponent {
1006
1017
  useExisting: forwardRef(() => SortableComponent)
1007
1018
  }
1008
1019
  ], queries: [{ propertyName: "defaultTemplateRef", predicate: TemplateRef }, { propertyName: "itemTemplateDirectiveRef", predicate: ItemTemplateDirective, read: TemplateRef }, { propertyName: "placeholderTemplateDirectiveRef", predicate: PlaceholderTemplateDirective, read: TemplateRef }], viewQueries: [{ propertyName: "noDataContainer", first: true, predicate: ["noDataRef"], descendants: true }, { propertyName: "hint", first: true, predicate: ["hint"], descendants: true }, { propertyName: "itemWrappers", predicate: ["itemWrapper"], descendants: true }, { propertyName: "draggables", predicate: DraggableDirective, descendants: true }], exportAs: ["kendoSortable"], usesOnChanges: true, ngImport: i0, template: `
1009
- <div #itemWrapper *ngFor="let item of _localData;let i=index"
1020
+ <div #itemWrapper *ngFor="let item of _localData; let i=index; trackBy: trackBy;"
1010
1021
  kendoDraggable
1011
1022
  role="listitem"
1012
1023
  [attr.aria-grabbed]="i===dragIndex"
@@ -1024,7 +1035,9 @@ export class SortableComponent {
1024
1035
 
1025
1036
  (focus)="focusHandler(i)"
1026
1037
  (blur)="blurHandler()"
1027
- (keydown)="keydownHandler($event)"
1038
+ [kendoEventsOutsideAngular]="{
1039
+ keydown: keydownHandler
1040
+ }"
1028
1041
  >
1029
1042
  <ng-container *ngIf="itemTemplateRef"
1030
1043
  [ngTemplateOutlet]="itemTemplate(i)"
@@ -1051,7 +1064,7 @@ export class SortableComponent {
1051
1064
  </ng-container>
1052
1065
  <ng-container *ngIf="!itemTemplateRef">{{_localData[dragIndex].item}}</ng-container>
1053
1066
  </div>
1054
- `, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: DraggableDirective, selector: "[kendoDraggable]", inputs: ["index", "disabled", "hidden"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
1067
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: DraggableDirective, selector: "[kendoDraggable]", inputs: ["index", "disabled", "hidden"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: EventsOutsideAngularDirective, selector: "[kendoEventsOutsideAngular]", inputs: ["kendoEventsOutsideAngular", "scope"] }] });
1055
1068
  }
1056
1069
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SortableComponent, decorators: [{
1057
1070
  type: Component,
@@ -1070,7 +1083,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1070
1083
  ],
1071
1084
  selector: 'kendo-sortable',
1072
1085
  template: `
1073
- <div #itemWrapper *ngFor="let item of _localData;let i=index"
1086
+ <div #itemWrapper *ngFor="let item of _localData; let i=index; trackBy: trackBy;"
1074
1087
  kendoDraggable
1075
1088
  role="listitem"
1076
1089
  [attr.aria-grabbed]="i===dragIndex"
@@ -1088,7 +1101,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1088
1101
 
1089
1102
  (focus)="focusHandler(i)"
1090
1103
  (blur)="blurHandler()"
1091
- (keydown)="keydownHandler($event)"
1104
+ [kendoEventsOutsideAngular]="{
1105
+ keydown: keydownHandler
1106
+ }"
1092
1107
  >
1093
1108
  <ng-container *ngIf="itemTemplateRef"
1094
1109
  [ngTemplateOutlet]="itemTemplate(i)"
@@ -1117,16 +1132,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1117
1132
  </div>
1118
1133
  `,
1119
1134
  standalone: true,
1120
- imports: [NgFor, DraggableDirective, NgClass, NgStyle, NgIf, NgTemplateOutlet]
1135
+ imports: [NgFor, DraggableDirective, NgClass, NgStyle, NgIf, NgTemplateOutlet, EventsOutsideAngularDirective]
1121
1136
  }]
1122
- }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i1.LocalizationService }, { type: i0.ElementRef }, { type: i2.SortableService }]; }, propDecorators: { tabIndex: [{
1137
+ }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i1.LocalizationService }, { type: i0.ElementRef }, { type: i2.SortableService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { tabIndex: [{
1138
+ type: Input
1139
+ }], trackBy: [{
1123
1140
  type: Input
1124
1141
  }], data: [{
1125
1142
  type: Input
1126
1143
  }], navigable: [{
1127
1144
  type: Input
1128
- }], navigatable: [{
1129
- type: Input
1130
1145
  }], animation: [{
1131
1146
  type: Input
1132
1147
  }], disabledIndexes: [{
@@ -4,7 +4,7 @@
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  import { Injectable, NgZone } from '@angular/core';
6
6
  import { isDocumentAvailable } from '@progress/kendo-angular-common';
7
- import { draggableFromEvent, isFocusable, widgetTarget } from './util';
7
+ import { draggableFromEvent, isFocusable, MINIMAL_DRAG_DISTANCE, widgetTarget } from './util';
8
8
  import { Subject } from 'rxjs';
9
9
  import { switchMap, filter, take, tap } from 'rxjs/operators';
10
10
  import * as i0 from "@angular/core";
@@ -202,6 +202,10 @@ export class SortableService {
202
202
  this.pressArgs = null;
203
203
  }
204
204
  drag(event) {
205
+ const distance = this.pressArgs && Math.sqrt((event.pageX - this.pressArgs.pageX) ** 2 + (event.pageY - this.pressArgs.pageY) ** 2);
206
+ if (distance && distance < MINIMAL_DRAG_DISTANCE) {
207
+ return;
208
+ }
205
209
  this.ngZone.run(() => {
206
210
  if (this.start()) {
207
211
  return;
package/esm2022/util.mjs CHANGED
@@ -6,6 +6,10 @@ import { focusableSelector, isDocumentAvailable } from '@progress/kendo-angular-
6
6
  const NODE_NAME_PREDICATES = {};
7
7
  const NODE_ATTR_PREDICATES = {};
8
8
  const focusableRegex = /^(?:a|input|select|option|textarea|button|object)$/i;
9
+ /**
10
+ * @hidden
11
+ */
12
+ export const MINIMAL_DRAG_DISTANCE = 5;
9
13
  /**
10
14
  * @hidden
11
15
  */
@@ -5,7 +5,7 @@
5
5
  import * as i0 from '@angular/core';
6
6
  import { Injectable, Directive, Input, HostBinding, QueryList, EventEmitter, forwardRef, TemplateRef, Component, ContentChildren, ViewChildren, ViewChild, Output, NgModule } from '@angular/core';
7
7
  import { Subject, merge } from 'rxjs';
8
- import { isDocumentAvailable, focusableSelector, isChanged, Keys } from '@progress/kendo-angular-common';
8
+ import { isDocumentAvailable, focusableSelector, isChanged, Keys, EventsOutsideAngularDirective } from '@progress/kendo-angular-common';
9
9
  import { filter, tap, take, switchMap } from 'rxjs/operators';
10
10
  import * as i1 from '@progress/kendo-angular-l10n';
11
11
  import { LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n';
@@ -16,6 +16,10 @@ import { NgFor, NgClass, NgStyle, NgIf, NgTemplateOutlet } from '@angular/common
16
16
  const NODE_NAME_PREDICATES = {};
17
17
  const NODE_ATTR_PREDICATES = {};
18
18
  const focusableRegex = /^(?:a|input|select|option|textarea|button|object)$/i;
19
+ /**
20
+ * @hidden
21
+ */
22
+ const MINIMAL_DRAG_DISTANCE = 5;
19
23
  /**
20
24
  * @hidden
21
25
  */
@@ -189,8 +193,8 @@ const packageMetadata = {
189
193
  productName: 'Kendo UI for Angular',
190
194
  productCode: 'KENDOUIANGULAR',
191
195
  productCodes: ['KENDOUIANGULAR'],
192
- publishDate: 1746081442,
193
- version: '19.0.0-develop.8',
196
+ publishDate: 1748362656,
197
+ version: '19.0.0',
194
198
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
195
199
  };
196
200
 
@@ -388,6 +392,10 @@ class SortableService {
388
392
  this.pressArgs = null;
389
393
  }
390
394
  drag(event) {
395
+ const distance = this.pressArgs && Math.sqrt((event.pageX - this.pressArgs.pageX) ** 2 + (event.pageY - this.pressArgs.pageY) ** 2);
396
+ if (distance && distance < MINIMAL_DRAG_DISTANCE) {
397
+ return;
398
+ }
391
399
  this.ngZone.run(() => {
392
400
  if (this.start()) {
393
401
  return;
@@ -660,10 +668,15 @@ class SortableComponent {
660
668
  renderer;
661
669
  changeDetector;
662
670
  localization;
671
+ cdr;
663
672
  /**
664
673
  * Specifies the tab index of the Sortable component.
665
674
  */
666
675
  tabIndex = null;
676
+ /**
677
+ * Configures how the Sortable component will track changes in its items collection.
678
+ */
679
+ trackBy = (_, idx) => idx;
667
680
  /**
668
681
  * Sets an array of any data that is used as a data source for the Sortable.
669
682
  */
@@ -679,17 +692,9 @@ class SortableComponent {
679
692
  }
680
693
  /**
681
694
  * Enables or disables the [keyboard navigation]({% slug keyboard_navigation_sortable %}).
682
- * @default false
683
- */
684
- navigable = false;
685
- /**
686
- * @hidden
687
- *
688
- * A misspelled alias for `navigable`.
695
+ * @default true
689
696
  */
690
- set navigatable(value) {
691
- this.navigable = value;
692
- }
697
+ navigable = true;
693
698
  /**
694
699
  * Enables or disables the built-in animations.
695
700
  * @default false
@@ -922,11 +927,12 @@ class SortableComponent {
922
927
  }
923
928
  return template;
924
929
  }
925
- constructor(ngZone, renderer, changeDetector, localization, wrapper, sortableService) {
930
+ constructor(ngZone, renderer, changeDetector, localization, wrapper, sortableService, cdr) {
926
931
  this.ngZone = ngZone;
927
932
  this.renderer = renderer;
928
933
  this.changeDetector = changeDetector;
929
934
  this.localization = localization;
935
+ this.cdr = cdr;
930
936
  validatePackage(packageMetadata);
931
937
  this.wrapper = wrapper.nativeElement;
932
938
  this.direction = localization.rtl ? 'rtl' : 'ltr';
@@ -1220,9 +1226,9 @@ class SortableComponent {
1220
1226
  /**
1221
1227
  * @hidden
1222
1228
  */
1223
- onEscapeHandler() {
1229
+ onEscapeHandler(event) {
1224
1230
  const focusableItems = this.focusableItems[this.prevActiveIndex];
1225
- const item = this.itemWrappers.toArray()[this.prevActiveIndex].nativeElement;
1231
+ const item = (event?.target).closest('[data-sortable-item]');
1226
1232
  focusableItems.forEach(focusableItem => {
1227
1233
  this.renderer.setAttribute(focusableItem, 'tabindex', '-1');
1228
1234
  });
@@ -1232,27 +1238,37 @@ class SortableComponent {
1232
1238
  /**
1233
1239
  * @hidden
1234
1240
  */
1235
- keydownHandler(event) {
1241
+ keydownHandler = (event) => {
1242
+ if (!this.navigable) {
1243
+ return;
1244
+ }
1245
+ this.cdr.markForCheck();
1246
+ const targetIsWrapper = this.itemWrappers.toArray().some((item) => item.nativeElement === event.target);
1236
1247
  const index = this.activeIndex === -1 ? this.prevActiveIndex : this.activeIndex;
1237
- const item = this.itemWrappers.toArray()[index].nativeElement;
1248
+ const item = this.itemWrappers.toArray()[index]?.nativeElement;
1238
1249
  const isItemFocused = document.activeElement === item;
1239
1250
  const hasFocus = this.activeIndex !== -1;
1240
1251
  const keyCode = event.keyCode;
1252
+ if (keyCode === Keys.Tab && !isItemFocused) {
1253
+ keepFocusWithinComponent(event, item);
1254
+ return;
1255
+ }
1256
+ if (keyCode === Keys.Escape && this.focusableItems.length > 0 && this.activeIndex === -1) {
1257
+ this.onEscapeHandler(event);
1258
+ return;
1259
+ }
1260
+ if (!targetIsWrapper) {
1261
+ return;
1262
+ }
1241
1263
  if (this.navigable && hasFocus) {
1242
1264
  if (keyCode >= Keys.ArrowLeft && keyCode <= Keys.ArrowDown) {
1243
- this.onArrowHandler(event, keyCode);
1265
+ this.ngZone.run(() => this.onArrowHandler(event, keyCode));
1244
1266
  }
1245
- if (keyCode === Keys.Enter && isItemFocused && this.focusableItems.length > 0) {
1267
+ else if (keyCode === Keys.Enter && isItemFocused && this.focusableItems.length > 0) {
1246
1268
  this.onEnterHandler(item);
1247
1269
  }
1248
1270
  }
1249
- if (keyCode === Keys.Tab && !isItemFocused) {
1250
- keepFocusWithinComponent(event, item);
1251
- }
1252
- if (keyCode === Keys.Escape && this.focusableItems.length > 0 && this.activeIndex === -1) {
1253
- this.onEscapeHandler();
1254
- }
1255
- }
1271
+ };
1256
1272
  /**
1257
1273
  * Removes the currently active item from the Data collection that the Sortable uses.
1258
1274
  */
@@ -1480,6 +1496,9 @@ class SortableComponent {
1480
1496
  .subscribe(({ rtl }) => this.direction = rtl ? 'rtl' : 'ltr');
1481
1497
  this.dragStartSubscription = this.onDragStartSubject
1482
1498
  .subscribe((event) => {
1499
+ if (!event.target) {
1500
+ return;
1501
+ }
1483
1502
  this.sortableService.originDraggable = event.target;
1484
1503
  this.sortableService.originIndex = event.target.index;
1485
1504
  this.sortableService.activeDraggable = event.target;
@@ -1617,8 +1636,8 @@ class SortableComponent {
1617
1636
  }
1618
1637
  }
1619
1638
  }
1620
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SortableComponent, deps: [{ token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i1.LocalizationService }, { token: i0.ElementRef }, { token: SortableService }], target: i0.ɵɵFactoryTarget.Component });
1621
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SortableComponent, isStandalone: true, selector: "kendo-sortable", inputs: { tabIndex: "tabIndex", data: "data", navigable: "navigable", navigatable: "navigatable", animation: "animation", disabledIndexes: "disabledIndexes", zone: "zone", acceptZones: "acceptZones", itemStyle: "itemStyle", emptyItemStyle: "emptyItemStyle", activeItemStyle: "activeItemStyle", disabledItemStyle: "disabledItemStyle", itemClass: "itemClass", activeItemClass: "activeItemClass", emptyItemClass: "emptyItemClass", disabledItemClass: "disabledItemClass", emptyText: "emptyText", activeIndex: "activeIndex" }, outputs: { dragStart: "dragStart", dragEnd: "dragEnd", dragOver: "dragOver", dragLeave: "dragLeave", dataMove: "dataMove", dataAdd: "dataAdd", dataRemove: "dataRemove", navigate: "navigate" }, host: { properties: { "style.touch-action": "this.touchAction", "attr.dir": "this.dir", "attr.role": "this.hostRole" } }, providers: [
1639
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SortableComponent, deps: [{ token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i1.LocalizationService }, { token: i0.ElementRef }, { token: SortableService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1640
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SortableComponent, isStandalone: true, selector: "kendo-sortable", inputs: { tabIndex: "tabIndex", trackBy: "trackBy", data: "data", navigable: "navigable", animation: "animation", disabledIndexes: "disabledIndexes", zone: "zone", acceptZones: "acceptZones", itemStyle: "itemStyle", emptyItemStyle: "emptyItemStyle", activeItemStyle: "activeItemStyle", disabledItemStyle: "disabledItemStyle", itemClass: "itemClass", activeItemClass: "activeItemClass", emptyItemClass: "emptyItemClass", disabledItemClass: "disabledItemClass", emptyText: "emptyText", activeIndex: "activeIndex" }, outputs: { dragStart: "dragStart", dragEnd: "dragEnd", dragOver: "dragOver", dragLeave: "dragLeave", dataMove: "dataMove", dataAdd: "dataAdd", dataRemove: "dataRemove", navigate: "navigate" }, host: { properties: { "style.touch-action": "this.touchAction", "attr.dir": "this.dir", "attr.role": "this.hostRole" } }, providers: [
1622
1641
  LocalizationService,
1623
1642
  {
1624
1643
  provide: L10N_PREFIX,
@@ -1629,7 +1648,7 @@ class SortableComponent {
1629
1648
  useExisting: forwardRef(() => SortableComponent)
1630
1649
  }
1631
1650
  ], queries: [{ propertyName: "defaultTemplateRef", predicate: TemplateRef }, { propertyName: "itemTemplateDirectiveRef", predicate: ItemTemplateDirective, read: TemplateRef }, { propertyName: "placeholderTemplateDirectiveRef", predicate: PlaceholderTemplateDirective, read: TemplateRef }], viewQueries: [{ propertyName: "noDataContainer", first: true, predicate: ["noDataRef"], descendants: true }, { propertyName: "hint", first: true, predicate: ["hint"], descendants: true }, { propertyName: "itemWrappers", predicate: ["itemWrapper"], descendants: true }, { propertyName: "draggables", predicate: DraggableDirective, descendants: true }], exportAs: ["kendoSortable"], usesOnChanges: true, ngImport: i0, template: `
1632
- <div #itemWrapper *ngFor="let item of _localData;let i=index"
1651
+ <div #itemWrapper *ngFor="let item of _localData; let i=index; trackBy: trackBy;"
1633
1652
  kendoDraggable
1634
1653
  role="listitem"
1635
1654
  [attr.aria-grabbed]="i===dragIndex"
@@ -1647,7 +1666,9 @@ class SortableComponent {
1647
1666
 
1648
1667
  (focus)="focusHandler(i)"
1649
1668
  (blur)="blurHandler()"
1650
- (keydown)="keydownHandler($event)"
1669
+ [kendoEventsOutsideAngular]="{
1670
+ keydown: keydownHandler
1671
+ }"
1651
1672
  >
1652
1673
  <ng-container *ngIf="itemTemplateRef"
1653
1674
  [ngTemplateOutlet]="itemTemplate(i)"
@@ -1674,7 +1695,7 @@ class SortableComponent {
1674
1695
  </ng-container>
1675
1696
  <ng-container *ngIf="!itemTemplateRef">{{_localData[dragIndex].item}}</ng-container>
1676
1697
  </div>
1677
- `, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: DraggableDirective, selector: "[kendoDraggable]", inputs: ["index", "disabled", "hidden"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
1698
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: DraggableDirective, selector: "[kendoDraggable]", inputs: ["index", "disabled", "hidden"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: EventsOutsideAngularDirective, selector: "[kendoEventsOutsideAngular]", inputs: ["kendoEventsOutsideAngular", "scope"] }] });
1678
1699
  }
1679
1700
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SortableComponent, decorators: [{
1680
1701
  type: Component,
@@ -1693,7 +1714,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1693
1714
  ],
1694
1715
  selector: 'kendo-sortable',
1695
1716
  template: `
1696
- <div #itemWrapper *ngFor="let item of _localData;let i=index"
1717
+ <div #itemWrapper *ngFor="let item of _localData; let i=index; trackBy: trackBy;"
1697
1718
  kendoDraggable
1698
1719
  role="listitem"
1699
1720
  [attr.aria-grabbed]="i===dragIndex"
@@ -1711,7 +1732,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1711
1732
 
1712
1733
  (focus)="focusHandler(i)"
1713
1734
  (blur)="blurHandler()"
1714
- (keydown)="keydownHandler($event)"
1735
+ [kendoEventsOutsideAngular]="{
1736
+ keydown: keydownHandler
1737
+ }"
1715
1738
  >
1716
1739
  <ng-container *ngIf="itemTemplateRef"
1717
1740
  [ngTemplateOutlet]="itemTemplate(i)"
@@ -1740,16 +1763,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1740
1763
  </div>
1741
1764
  `,
1742
1765
  standalone: true,
1743
- imports: [NgFor, DraggableDirective, NgClass, NgStyle, NgIf, NgTemplateOutlet]
1766
+ imports: [NgFor, DraggableDirective, NgClass, NgStyle, NgIf, NgTemplateOutlet, EventsOutsideAngularDirective]
1744
1767
  }]
1745
- }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i1.LocalizationService }, { type: i0.ElementRef }, { type: SortableService }]; }, propDecorators: { tabIndex: [{
1768
+ }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i1.LocalizationService }, { type: i0.ElementRef }, { type: SortableService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { tabIndex: [{
1769
+ type: Input
1770
+ }], trackBy: [{
1746
1771
  type: Input
1747
1772
  }], data: [{
1748
1773
  type: Input
1749
1774
  }], navigable: [{
1750
1775
  type: Input
1751
- }], navigatable: [{
1752
- type: Input
1753
1776
  }], animation: [{
1754
1777
  type: Input
1755
1778
  }], disabledIndexes: [{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@progress/kendo-angular-sortable",
3
- "version": "19.0.0-develop.8",
3
+ "version": "19.0.0",
4
4
  "description": "A Sortable Component for Angular",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "Progress",
@@ -19,7 +19,7 @@
19
19
  "package": {
20
20
  "productName": "Kendo UI for Angular",
21
21
  "productCode": "KENDOUIANGULAR",
22
- "publishDate": 1746081442,
22
+ "publishDate": 1748362656,
23
23
  "licensingDocsUrl": "https://www.telerik.com/kendo-angular-ui/my-license/"
24
24
  }
25
25
  },
@@ -29,13 +29,13 @@
29
29
  "@angular/core": "16 - 19",
30
30
  "@angular/platform-browser": "16 - 19",
31
31
  "@progress/kendo-licensing": "^1.5.0",
32
- "@progress/kendo-angular-common": "19.0.0-develop.8",
33
- "@progress/kendo-angular-l10n": "19.0.0-develop.8",
32
+ "@progress/kendo-angular-common": "19.0.0",
33
+ "@progress/kendo-angular-l10n": "19.0.0",
34
34
  "rxjs": "^6.5.3 || ^7.0.0"
35
35
  },
36
36
  "dependencies": {
37
37
  "tslib": "^2.3.1",
38
- "@progress/kendo-angular-schematics": "19.0.0-develop.8",
38
+ "@progress/kendo-angular-schematics": "19.0.0",
39
39
  "@progress/kendo-draggable": "^3.0.2"
40
40
  },
41
41
  "schematics": "./schematics/collection.json",
@@ -2,7 +2,7 @@
2
2
  * Copyright © 2025 Progress Software Corporation. All rights reserved.
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
- import { QueryList, TemplateRef, ElementRef, EventEmitter, OnInit, OnDestroy, AfterViewChecked, AfterContentInit, NgZone, ChangeDetectorRef, SimpleChanges, OnChanges, Renderer2, AfterViewInit } from '@angular/core';
5
+ import { QueryList, TemplateRef, ElementRef, EventEmitter, OnInit, OnDestroy, AfterViewChecked, AfterContentInit, NgZone, ChangeDetectorRef, SimpleChanges, OnChanges, Renderer2, AfterViewInit, TrackByFunction } from '@angular/core';
6
6
  import { Subject } from 'rxjs';
7
7
  import { LocalizationService } from '@progress/kendo-angular-l10n';
8
8
  import { SortableService } from './sortable.service';
@@ -20,10 +20,15 @@ export declare class SortableComponent implements OnInit, OnDestroy, OnChanges,
20
20
  private renderer;
21
21
  private changeDetector;
22
22
  private localization;
23
+ private cdr;
23
24
  /**
24
25
  * Specifies the tab index of the Sortable component.
25
26
  */
26
27
  tabIndex: number;
28
+ /**
29
+ * Configures how the Sortable component will track changes in its items collection.
30
+ */
31
+ trackBy: TrackByFunction<any>;
27
32
  /**
28
33
  * Sets an array of any data that is used as a data source for the Sortable.
29
34
  */
@@ -31,15 +36,9 @@ export declare class SortableComponent implements OnInit, OnDestroy, OnChanges,
31
36
  get data(): Array<any>;
32
37
  /**
33
38
  * Enables or disables the [keyboard navigation]({% slug keyboard_navigation_sortable %}).
34
- * @default false
39
+ * @default true
35
40
  */
36
41
  navigable: boolean;
37
- /**
38
- * @hidden
39
- *
40
- * A misspelled alias for `navigable`.
41
- */
42
- set navigatable(value: boolean);
43
42
  /**
44
43
  * Enables or disables the built-in animations.
45
44
  * @default false
@@ -266,7 +265,7 @@ export declare class SortableComponent implements OnInit, OnDestroy, OnChanges,
266
265
  * @hidden
267
266
  */
268
267
  itemTemplate(index: number): TemplateRef<any>;
269
- constructor(ngZone: NgZone, renderer: Renderer2, changeDetector: ChangeDetectorRef, localization: LocalizationService, wrapper: ElementRef, sortableService: SortableService);
268
+ constructor(ngZone: NgZone, renderer: Renderer2, changeDetector: ChangeDetectorRef, localization: LocalizationService, wrapper: ElementRef, sortableService: SortableService, cdr: ChangeDetectorRef);
270
269
  ngOnInit(): void;
271
270
  ngAfterViewInit(): void;
272
271
  ngOnChanges(changes: SimpleChanges): void;
@@ -356,11 +355,11 @@ export declare class SortableComponent implements OnInit, OnDestroy, OnChanges,
356
355
  /**
357
356
  * @hidden
358
357
  */
359
- onEscapeHandler(): void;
358
+ onEscapeHandler(event: KeyboardEvent): void;
360
359
  /**
361
360
  * @hidden
362
361
  */
363
- keydownHandler(event: any): void;
362
+ keydownHandler: (event: KeyboardEvent) => void;
364
363
  /**
365
364
  * Removes the currently active item from the Data collection that the Sortable uses.
366
365
  */
@@ -433,5 +432,5 @@ export declare class SortableComponent implements OnInit, OnDestroy, OnChanges,
433
432
  private placeHolderItemData;
434
433
  private fixFocus;
435
434
  static ɵfac: i0.ɵɵFactoryDeclaration<SortableComponent, never>;
436
- static ɵcmp: i0.ɵɵComponentDeclaration<SortableComponent, "kendo-sortable", ["kendoSortable"], { "tabIndex": { "alias": "tabIndex"; "required": false; }; "data": { "alias": "data"; "required": false; }; "navigable": { "alias": "navigable"; "required": false; }; "navigatable": { "alias": "navigatable"; "required": false; }; "animation": { "alias": "animation"; "required": false; }; "disabledIndexes": { "alias": "disabledIndexes"; "required": false; }; "zone": { "alias": "zone"; "required": false; }; "acceptZones": { "alias": "acceptZones"; "required": false; }; "itemStyle": { "alias": "itemStyle"; "required": false; }; "emptyItemStyle": { "alias": "emptyItemStyle"; "required": false; }; "activeItemStyle": { "alias": "activeItemStyle"; "required": false; }; "disabledItemStyle": { "alias": "disabledItemStyle"; "required": false; }; "itemClass": { "alias": "itemClass"; "required": false; }; "activeItemClass": { "alias": "activeItemClass"; "required": false; }; "emptyItemClass": { "alias": "emptyItemClass"; "required": false; }; "disabledItemClass": { "alias": "disabledItemClass"; "required": false; }; "emptyText": { "alias": "emptyText"; "required": false; }; "activeIndex": { "alias": "activeIndex"; "required": false; }; }, { "dragStart": "dragStart"; "dragEnd": "dragEnd"; "dragOver": "dragOver"; "dragLeave": "dragLeave"; "dataMove": "dataMove"; "dataAdd": "dataAdd"; "dataRemove": "dataRemove"; "navigate": "navigate"; }, ["defaultTemplateRef", "itemTemplateDirectiveRef", "placeholderTemplateDirectiveRef"], never, true, never>;
435
+ static ɵcmp: i0.ɵɵComponentDeclaration<SortableComponent, "kendo-sortable", ["kendoSortable"], { "tabIndex": { "alias": "tabIndex"; "required": false; }; "trackBy": { "alias": "trackBy"; "required": false; }; "data": { "alias": "data"; "required": false; }; "navigable": { "alias": "navigable"; "required": false; }; "animation": { "alias": "animation"; "required": false; }; "disabledIndexes": { "alias": "disabledIndexes"; "required": false; }; "zone": { "alias": "zone"; "required": false; }; "acceptZones": { "alias": "acceptZones"; "required": false; }; "itemStyle": { "alias": "itemStyle"; "required": false; }; "emptyItemStyle": { "alias": "emptyItemStyle"; "required": false; }; "activeItemStyle": { "alias": "activeItemStyle"; "required": false; }; "disabledItemStyle": { "alias": "disabledItemStyle"; "required": false; }; "itemClass": { "alias": "itemClass"; "required": false; }; "activeItemClass": { "alias": "activeItemClass"; "required": false; }; "emptyItemClass": { "alias": "emptyItemClass"; "required": false; }; "disabledItemClass": { "alias": "disabledItemClass"; "required": false; }; "emptyText": { "alias": "emptyText"; "required": false; }; "activeIndex": { "alias": "activeIndex"; "required": false; }; }, { "dragStart": "dragStart"; "dragEnd": "dragEnd"; "dragOver": "dragOver"; "dragLeave": "dragLeave"; "dataMove": "dataMove"; "dataAdd": "dataAdd"; "dataRemove": "dataRemove"; "navigate": "navigate"; }, ["defaultTemplateRef", "itemTemplateDirectiveRef", "placeholderTemplateDirectiveRef"], never, true, never>;
437
436
  }
package/util.d.ts CHANGED
@@ -2,6 +2,10 @@
2
2
  * Copyright © 2025 Progress Software Corporation. All rights reserved.
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
+ /**
6
+ * @hidden
7
+ */
8
+ export declare const MINIMAL_DRAG_DISTANCE = 5;
5
9
  /**
6
10
  * @hidden
7
11
  */