@progress/kendo-angular-common 21.1.1-develop.2 → 21.2.0-develop.10

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.
package/esm2022/index.mjs CHANGED
@@ -11,7 +11,7 @@ export * from './utils';
11
11
  export * from './enums';
12
12
  export * from './utils/focusable-selectors';
13
13
  export * from './utils/ng-class-parser';
14
- export * from './utils/numpad-keys-normalizer';
14
+ export * from './utils/keys-normalizer';
15
15
  export * from './utils/getter';
16
16
  export * from './utils/setter';
17
17
  export * from './watermark';
@@ -8,7 +8,7 @@ import { MultiTabStop } from "./toggle-button-tab-stop";
8
8
  import { Subscription } from "rxjs";
9
9
  import { take } from "rxjs/operators";
10
10
  import { Keys } from "../enums";
11
- import { normalizeNumpadKeys } from "../utils/numpad-keys-normalizer";
11
+ import { normalizeKeys } from "../utils/keys-normalizer";
12
12
  import * as i0 from "@angular/core";
13
13
  import * as i1 from "./toggle-button-tab-stop";
14
14
  const tags = ['kendo-splitbutton', 'kendo-combobox', 'kendo-multicolumncombobox', 'kendo-datepicker', 'kendo-timepicker', 'kendo-datetimepicker'];
@@ -158,7 +158,7 @@ export class ToggleButtonTabStopDirective {
158
158
  this.renderer.removeStyle(this.button, 'box-shadow');
159
159
  };
160
160
  onClick = (e) => {
161
- const code = normalizeNumpadKeys(e);
161
+ const code = normalizeKeys(e);
162
162
  const splitButtonToggleEnter = e instanceof KeyboardEvent && code === Keys.Enter;
163
163
  const isClick = e instanceof PointerEvent;
164
164
  if (splitButtonToggleEnter || isClick) {
@@ -166,7 +166,7 @@ export class ToggleButtonTabStopDirective {
166
166
  }
167
167
  };
168
168
  onKeyDown = (e) => {
169
- const code = normalizeNumpadKeys(e);
169
+ const code = normalizeKeys(e);
170
170
  if (code === Keys.ArrowDown && e.altKey) {
171
171
  e.stopImmediatePropagation();
172
172
  this.focusButton = true;
@@ -0,0 +1,95 @@
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
+ import { Keys } from "../enums";
6
+ /**
7
+ * @hidden
8
+ *
9
+ * Maps keyCode values (65-90) to Keys enum values (KeyA-KeyZ).
10
+ * Used to handle letter keys correctly across different keyboard layouts.
11
+ */
12
+ const keyCodeToKeysMap = {
13
+ 65: Keys.KeyA,
14
+ 66: Keys.KeyB,
15
+ 67: Keys.KeyC,
16
+ 68: Keys.KeyD,
17
+ 69: Keys.KeyE,
18
+ 70: Keys.KeyF,
19
+ 71: Keys.KeyG,
20
+ 72: Keys.KeyH,
21
+ 73: Keys.KeyI,
22
+ 74: Keys.KeyJ,
23
+ 75: Keys.KeyK,
24
+ 76: Keys.KeyL,
25
+ 77: Keys.KeyM,
26
+ 78: Keys.KeyN,
27
+ 79: Keys.KeyO,
28
+ 80: Keys.KeyP,
29
+ 81: Keys.KeyQ,
30
+ 82: Keys.KeyR,
31
+ 83: Keys.KeyS,
32
+ 84: Keys.KeyT,
33
+ 85: Keys.KeyU,
34
+ 86: Keys.KeyV,
35
+ 87: Keys.KeyW,
36
+ 88: Keys.KeyX,
37
+ 89: Keys.KeyY,
38
+ 90: Keys.KeyZ
39
+ };
40
+ /**
41
+ * @hidden
42
+ *
43
+ * Normalizes keyboard events to ensure consistent key handling across different keyboard layouts.
44
+ *
45
+ * This function addresses the following scenarios:
46
+ * 1. On some keyboards, PageUp/Down, Home/End, and arrow keys are mapped to Numpad keys
47
+ * 2. For letter keys (KeyA-KeyZ), checks the deprecated keyCode property to handle non-QWERTY layouts
48
+ * (e.g., AZERTY, QWERTZ) where event.code may not match the expected letter
49
+ *
50
+ * @param event - The keyboard event to normalize
51
+ * @returns The normalized key code string (e.g., 'KeyA', 'ArrowDown', 'Enter')
52
+ *
53
+ * @example
54
+ * // On an AZERTY layout, pressing Ctrl+A (where 'A' is physically at 'Q' position)
55
+ * // event.code = 'KeyQ', event.keyCode = 65
56
+ * const code = normalizeKeys(event); // Returns 'KeyA'
57
+ */
58
+ export const normalizeKeys = (event) => {
59
+ const keyCode = event.keyCode;
60
+ if (keyCode >= 65 && keyCode <= 90) {
61
+ const normalizedKey = keyCodeToKeysMap[keyCode];
62
+ if (normalizedKey) {
63
+ return normalizedKey;
64
+ }
65
+ }
66
+ // Handle numpad keys that may be mapped to navigation keys
67
+ if (event.code === Keys.Numpad1 && event.key === Keys.End) {
68
+ return Keys.End;
69
+ }
70
+ if (event.code === Keys.Numpad2 && event.key === Keys.ArrowDown) {
71
+ return Keys.ArrowDown;
72
+ }
73
+ if (event.code === Keys.Numpad3 && event.key === Keys.PageDown) {
74
+ return Keys.PageDown;
75
+ }
76
+ if (event.code === Keys.Numpad4 && event.key === Keys.ArrowLeft) {
77
+ return Keys.ArrowLeft;
78
+ }
79
+ if (event.code === Keys.Numpad6 && event.key === Keys.ArrowRight) {
80
+ return Keys.ArrowRight;
81
+ }
82
+ if (event.code === Keys.Numpad7 && event.key === Keys.Home) {
83
+ return Keys.Home;
84
+ }
85
+ if (event.code === Keys.Numpad8 && event.key === Keys.ArrowUp) {
86
+ return Keys.ArrowUp;
87
+ }
88
+ if (event.code === Keys.Numpad9 && event.key === Keys.PageUp) {
89
+ return Keys.PageUp;
90
+ }
91
+ if (event.code === Keys.NumpadEnter) {
92
+ return Keys.Enter;
93
+ }
94
+ return event.code;
95
+ };
@@ -5,7 +5,7 @@
5
5
  import { Component, ElementRef, HostBinding, Input, ViewChild } from '@angular/core';
6
6
  import { watermarkStyles, bannerStyles, licenseKeyUrl, buttonStyles } from './utils';
7
7
  import { isDocumentAvailable } from '../utils';
8
- import { NgIf, NgStyle } from '@angular/common';
8
+ import { NgStyle } from '@angular/common';
9
9
  import * as i0 from "@angular/core";
10
10
  let bannerPresentOnPage = false;
11
11
  /**
@@ -43,59 +43,67 @@ export class WatermarkOverlayComponent {
43
43
  return isDocumentAvailable() && !!this.banner?.nativeElement;
44
44
  }
45
45
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WatermarkOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
46
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: WatermarkOverlayComponent, isStandalone: true, selector: "div[kendoWatermarkOverlay]", inputs: { licenseMessage: "licenseMessage" }, host: { properties: { "style": "this.watermarkStyle" } }, viewQueries: [{ propertyName: "banner", first: true, predicate: ["banner"], descendants: true }], ngImport: i0, template: `
47
- <div #banner *ngIf="isOpen && bannerMounted" [ngStyle]="bannerStyles">
46
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: WatermarkOverlayComponent, isStandalone: true, selector: "div[kendoWatermarkOverlay]", inputs: { licenseMessage: "licenseMessage" }, host: { properties: { "style": "this.watermarkStyle" } }, viewQueries: [{ propertyName: "banner", first: true, predicate: ["banner"], descendants: true }], ngImport: i0, template: `
47
+ @if (isOpen && bannerMounted) {
48
+ <div #banner [ngStyle]="bannerStyles">
48
49
  <span [ngStyle]="{ display: 'flex', alignSelf: 'center', marginRight: '8px' }">
49
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
50
- <path fill-rule="evenodd" clip-rule="evenodd" d="M8 1L0 15H16L8 1ZM7 6V11H9V6H7ZM7 14V12H9V14H7Z" fill="#1E1E1E"/>
51
- </svg>
50
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
51
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M8 1L0 15H16L8 1ZM7 6V11H9V6H7ZM7 14V12H9V14H7Z" fill="#1E1E1E"/>
52
+ </svg>
52
53
  </span>
53
-
54
- <span *ngIf="licenseMessage" [innerHtml]="licenseMessage"></span>
55
- <span *ngIf="!licenseMessage">
54
+ @if (licenseMessage) {
55
+ <span [innerHtml]="licenseMessage"></span>
56
+ }
57
+ @if (!licenseMessage) {
58
+ <span>
56
59
  We couldn't verify your <a [href]="licenseKeyUrl">license key</a> for Kendo UI for Angular. Please see the browser
57
60
  console for details and resolution steps.
58
- </span>
59
-
61
+ </span>
62
+ }
60
63
  <div [ngStyle]="{ display: 'flex', alignItems: 'center', marginLeft: '24px' }">
61
- <button title='Close' [ngStyle]="buttonStyles" (click)="closeBanner()">
62
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
63
- <path d="M13 4.41562L9.41563 8L13 11.5844L11.5844 13L8 9.41563L4.41562 13L3 11.5844L6.58437 8L3 4.41562L4.41562 3L8 6.58437L11.5844 3L13 4.41562Z" fill="#1E1E1E"/>
64
- </svg>
65
- </button>
64
+ <button title='Close' [ngStyle]="buttonStyles" (click)="closeBanner()">
65
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
66
+ <path d="M13 4.41562L9.41563 8L13 11.5844L11.5844 13L8 9.41563L4.41562 13L3 11.5844L6.58437 8L3 4.41562L4.41562 3L8 6.58437L11.5844 3L13 4.41562Z" fill="#1E1E1E"/>
67
+ </svg>
68
+ </button>
66
69
  </div>
67
- </div>
68
- `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
70
+ </div>
71
+ }
72
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
69
73
  }
70
74
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WatermarkOverlayComponent, decorators: [{
71
75
  type: Component,
72
76
  args: [{
73
77
  selector: 'div[kendoWatermarkOverlay]',
74
78
  template: `
75
- <div #banner *ngIf="isOpen && bannerMounted" [ngStyle]="bannerStyles">
79
+ @if (isOpen && bannerMounted) {
80
+ <div #banner [ngStyle]="bannerStyles">
76
81
  <span [ngStyle]="{ display: 'flex', alignSelf: 'center', marginRight: '8px' }">
77
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
78
- <path fill-rule="evenodd" clip-rule="evenodd" d="M8 1L0 15H16L8 1ZM7 6V11H9V6H7ZM7 14V12H9V14H7Z" fill="#1E1E1E"/>
79
- </svg>
82
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
83
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M8 1L0 15H16L8 1ZM7 6V11H9V6H7ZM7 14V12H9V14H7Z" fill="#1E1E1E"/>
84
+ </svg>
80
85
  </span>
81
-
82
- <span *ngIf="licenseMessage" [innerHtml]="licenseMessage"></span>
83
- <span *ngIf="!licenseMessage">
86
+ @if (licenseMessage) {
87
+ <span [innerHtml]="licenseMessage"></span>
88
+ }
89
+ @if (!licenseMessage) {
90
+ <span>
84
91
  We couldn't verify your <a [href]="licenseKeyUrl">license key</a> for Kendo UI for Angular. Please see the browser
85
92
  console for details and resolution steps.
86
- </span>
87
-
93
+ </span>
94
+ }
88
95
  <div [ngStyle]="{ display: 'flex', alignItems: 'center', marginLeft: '24px' }">
89
- <button title='Close' [ngStyle]="buttonStyles" (click)="closeBanner()">
90
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
91
- <path d="M13 4.41562L9.41563 8L13 11.5844L11.5844 13L8 9.41563L4.41562 13L3 11.5844L6.58437 8L3 4.41562L4.41562 3L8 6.58437L11.5844 3L13 4.41562Z" fill="#1E1E1E"/>
92
- </svg>
93
- </button>
96
+ <button title='Close' [ngStyle]="buttonStyles" (click)="closeBanner()">
97
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
98
+ <path d="M13 4.41562L9.41563 8L13 11.5844L11.5844 13L8 9.41563L4.41562 13L3 11.5844L6.58437 8L3 4.41562L4.41562 3L8 6.58437L11.5844 3L13 4.41562Z" fill="#1E1E1E"/>
99
+ </svg>
100
+ </button>
94
101
  </div>
95
- </div>
96
- `,
102
+ </div>
103
+ }
104
+ `,
97
105
  standalone: true,
98
- imports: [NgIf, NgStyle]
106
+ imports: [NgStyle]
99
107
  }]
100
108
  }], propDecorators: { watermarkStyle: [{
101
109
  type: HostBinding,
@@ -8,7 +8,7 @@ import { detectDesktopBrowser, detectMobileOS } from '@progress/kendo-common';
8
8
  import { take, auditTime } from 'rxjs/operators';
9
9
  import { Draggable } from '@progress/kendo-draggable';
10
10
  import { merge, fromEvent, from, Subscription } from 'rxjs';
11
- import { NgIf, NgStyle } from '@angular/common';
11
+ import { NgStyle } from '@angular/common';
12
12
  import { getLicenseStatus } from '@progress/kendo-licensing';
13
13
 
14
14
  /**
@@ -891,9 +891,64 @@ const focusableSelector = [
891
891
  /**
892
892
  * @hidden
893
893
  *
894
- * On some keyboards, PageUp/Down, Home/End, and arrow keys are mapped to Numpad keys
894
+ * Maps keyCode values (65-90) to Keys enum values (KeyA-KeyZ).
895
+ * Used to handle letter keys correctly across different keyboard layouts.
895
896
  */
896
- const normalizeNumpadKeys = (event) => {
897
+ const keyCodeToKeysMap = {
898
+ 65: Keys.KeyA,
899
+ 66: Keys.KeyB,
900
+ 67: Keys.KeyC,
901
+ 68: Keys.KeyD,
902
+ 69: Keys.KeyE,
903
+ 70: Keys.KeyF,
904
+ 71: Keys.KeyG,
905
+ 72: Keys.KeyH,
906
+ 73: Keys.KeyI,
907
+ 74: Keys.KeyJ,
908
+ 75: Keys.KeyK,
909
+ 76: Keys.KeyL,
910
+ 77: Keys.KeyM,
911
+ 78: Keys.KeyN,
912
+ 79: Keys.KeyO,
913
+ 80: Keys.KeyP,
914
+ 81: Keys.KeyQ,
915
+ 82: Keys.KeyR,
916
+ 83: Keys.KeyS,
917
+ 84: Keys.KeyT,
918
+ 85: Keys.KeyU,
919
+ 86: Keys.KeyV,
920
+ 87: Keys.KeyW,
921
+ 88: Keys.KeyX,
922
+ 89: Keys.KeyY,
923
+ 90: Keys.KeyZ
924
+ };
925
+ /**
926
+ * @hidden
927
+ *
928
+ * Normalizes keyboard events to ensure consistent key handling across different keyboard layouts.
929
+ *
930
+ * This function addresses the following scenarios:
931
+ * 1. On some keyboards, PageUp/Down, Home/End, and arrow keys are mapped to Numpad keys
932
+ * 2. For letter keys (KeyA-KeyZ), checks the deprecated keyCode property to handle non-QWERTY layouts
933
+ * (e.g., AZERTY, QWERTZ) where event.code may not match the expected letter
934
+ *
935
+ * @param event - The keyboard event to normalize
936
+ * @returns The normalized key code string (e.g., 'KeyA', 'ArrowDown', 'Enter')
937
+ *
938
+ * @example
939
+ * // On an AZERTY layout, pressing Ctrl+A (where 'A' is physically at 'Q' position)
940
+ * // event.code = 'KeyQ', event.keyCode = 65
941
+ * const code = normalizeKeys(event); // Returns 'KeyA'
942
+ */
943
+ const normalizeKeys = (event) => {
944
+ const keyCode = event.keyCode;
945
+ if (keyCode >= 65 && keyCode <= 90) {
946
+ const normalizedKey = keyCodeToKeysMap[keyCode];
947
+ if (normalizedKey) {
948
+ return normalizedKey;
949
+ }
950
+ }
951
+ // Handle numpad keys that may be mapped to navigation keys
897
952
  if (event.code === Keys.Numpad1 && event.key === Keys.End) {
898
953
  return Keys.End;
899
954
  }
@@ -1064,59 +1119,67 @@ class WatermarkOverlayComponent {
1064
1119
  return isDocumentAvailable() && !!this.banner?.nativeElement;
1065
1120
  }
1066
1121
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WatermarkOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1067
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: WatermarkOverlayComponent, isStandalone: true, selector: "div[kendoWatermarkOverlay]", inputs: { licenseMessage: "licenseMessage" }, host: { properties: { "style": "this.watermarkStyle" } }, viewQueries: [{ propertyName: "banner", first: true, predicate: ["banner"], descendants: true }], ngImport: i0, template: `
1068
- <div #banner *ngIf="isOpen && bannerMounted" [ngStyle]="bannerStyles">
1122
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: WatermarkOverlayComponent, isStandalone: true, selector: "div[kendoWatermarkOverlay]", inputs: { licenseMessage: "licenseMessage" }, host: { properties: { "style": "this.watermarkStyle" } }, viewQueries: [{ propertyName: "banner", first: true, predicate: ["banner"], descendants: true }], ngImport: i0, template: `
1123
+ @if (isOpen && bannerMounted) {
1124
+ <div #banner [ngStyle]="bannerStyles">
1069
1125
  <span [ngStyle]="{ display: 'flex', alignSelf: 'center', marginRight: '8px' }">
1070
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
1071
- <path fill-rule="evenodd" clip-rule="evenodd" d="M8 1L0 15H16L8 1ZM7 6V11H9V6H7ZM7 14V12H9V14H7Z" fill="#1E1E1E"/>
1072
- </svg>
1126
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
1127
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M8 1L0 15H16L8 1ZM7 6V11H9V6H7ZM7 14V12H9V14H7Z" fill="#1E1E1E"/>
1128
+ </svg>
1073
1129
  </span>
1074
-
1075
- <span *ngIf="licenseMessage" [innerHtml]="licenseMessage"></span>
1076
- <span *ngIf="!licenseMessage">
1130
+ @if (licenseMessage) {
1131
+ <span [innerHtml]="licenseMessage"></span>
1132
+ }
1133
+ @if (!licenseMessage) {
1134
+ <span>
1077
1135
  We couldn't verify your <a [href]="licenseKeyUrl">license key</a> for Kendo UI for Angular. Please see the browser
1078
1136
  console for details and resolution steps.
1079
- </span>
1080
-
1137
+ </span>
1138
+ }
1081
1139
  <div [ngStyle]="{ display: 'flex', alignItems: 'center', marginLeft: '24px' }">
1082
- <button title='Close' [ngStyle]="buttonStyles" (click)="closeBanner()">
1083
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
1084
- <path d="M13 4.41562L9.41563 8L13 11.5844L11.5844 13L8 9.41563L4.41562 13L3 11.5844L6.58437 8L3 4.41562L4.41562 3L8 6.58437L11.5844 3L13 4.41562Z" fill="#1E1E1E"/>
1085
- </svg>
1086
- </button>
1140
+ <button title='Close' [ngStyle]="buttonStyles" (click)="closeBanner()">
1141
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
1142
+ <path d="M13 4.41562L9.41563 8L13 11.5844L11.5844 13L8 9.41563L4.41562 13L3 11.5844L6.58437 8L3 4.41562L4.41562 3L8 6.58437L11.5844 3L13 4.41562Z" fill="#1E1E1E"/>
1143
+ </svg>
1144
+ </button>
1087
1145
  </div>
1088
- </div>
1089
- `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
1146
+ </div>
1147
+ }
1148
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
1090
1149
  }
1091
1150
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: WatermarkOverlayComponent, decorators: [{
1092
1151
  type: Component,
1093
1152
  args: [{
1094
1153
  selector: 'div[kendoWatermarkOverlay]',
1095
1154
  template: `
1096
- <div #banner *ngIf="isOpen && bannerMounted" [ngStyle]="bannerStyles">
1155
+ @if (isOpen && bannerMounted) {
1156
+ <div #banner [ngStyle]="bannerStyles">
1097
1157
  <span [ngStyle]="{ display: 'flex', alignSelf: 'center', marginRight: '8px' }">
1098
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
1099
- <path fill-rule="evenodd" clip-rule="evenodd" d="M8 1L0 15H16L8 1ZM7 6V11H9V6H7ZM7 14V12H9V14H7Z" fill="#1E1E1E"/>
1100
- </svg>
1158
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
1159
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M8 1L0 15H16L8 1ZM7 6V11H9V6H7ZM7 14V12H9V14H7Z" fill="#1E1E1E"/>
1160
+ </svg>
1101
1161
  </span>
1102
-
1103
- <span *ngIf="licenseMessage" [innerHtml]="licenseMessage"></span>
1104
- <span *ngIf="!licenseMessage">
1162
+ @if (licenseMessage) {
1163
+ <span [innerHtml]="licenseMessage"></span>
1164
+ }
1165
+ @if (!licenseMessage) {
1166
+ <span>
1105
1167
  We couldn't verify your <a [href]="licenseKeyUrl">license key</a> for Kendo UI for Angular. Please see the browser
1106
1168
  console for details and resolution steps.
1107
- </span>
1108
-
1169
+ </span>
1170
+ }
1109
1171
  <div [ngStyle]="{ display: 'flex', alignItems: 'center', marginLeft: '24px' }">
1110
- <button title='Close' [ngStyle]="buttonStyles" (click)="closeBanner()">
1111
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
1112
- <path d="M13 4.41562L9.41563 8L13 11.5844L11.5844 13L8 9.41563L4.41562 13L3 11.5844L6.58437 8L3 4.41562L4.41562 3L8 6.58437L11.5844 3L13 4.41562Z" fill="#1E1E1E"/>
1113
- </svg>
1114
- </button>
1172
+ <button title='Close' [ngStyle]="buttonStyles" (click)="closeBanner()">
1173
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
1174
+ <path d="M13 4.41562L9.41563 8L13 11.5844L11.5844 13L8 9.41563L4.41562 13L3 11.5844L6.58437 8L3 4.41562L4.41562 3L8 6.58437L11.5844 3L13 4.41562Z" fill="#1E1E1E"/>
1175
+ </svg>
1176
+ </button>
1115
1177
  </div>
1116
- </div>
1117
- `,
1178
+ </div>
1179
+ }
1180
+ `,
1118
1181
  standalone: true,
1119
- imports: [NgIf, NgStyle]
1182
+ imports: [NgStyle]
1120
1183
  }]
1121
1184
  }], propDecorators: { watermarkStyle: [{
1122
1185
  type: HostBinding,
@@ -1523,7 +1586,7 @@ class ToggleButtonTabStopDirective {
1523
1586
  this.renderer.removeStyle(this.button, 'box-shadow');
1524
1587
  };
1525
1588
  onClick = (e) => {
1526
- const code = normalizeNumpadKeys(e);
1589
+ const code = normalizeKeys(e);
1527
1590
  const splitButtonToggleEnter = e instanceof KeyboardEvent && code === Keys.Enter;
1528
1591
  const isClick = e instanceof PointerEvent;
1529
1592
  if (splitButtonToggleEnter || isClick) {
@@ -1531,7 +1594,7 @@ class ToggleButtonTabStopDirective {
1531
1594
  }
1532
1595
  };
1533
1596
  onKeyDown = (e) => {
1534
- const code = normalizeNumpadKeys(e);
1597
+ const code = normalizeKeys(e);
1535
1598
  if (code === Keys.ArrowDown && e.altKey) {
1536
1599
  e.stopImmediatePropagation();
1537
1600
  this.focusButton = true;
@@ -1723,5 +1786,5 @@ const replaceMessagePlaceholder = (message, name, value) => (message ?? '').repl
1723
1786
  * Generated bundle index. Do not edit.
1724
1787
  */
1725
1788
 
1726
- export { DraggableDirective, EventsOutsideAngularDirective, KENDO_ADORNMENTS, KENDO_COMMON, KENDO_DRAGGABLE, KENDO_EVENTS, KENDO_RESIZESENSOR, KENDO_TEMPLATE_CONTEXT, KENDO_TOGGLEBUTTONTABSTOP, KENDO_WATERMARK, KendoInput, Keys, MultiTabStop, PrefixTemplateDirective, PreventableEvent, ResizeBatchService, ResizeCompatService, ResizeObserverService, ResizeSensorComponent, ScrollbarWidthService, SeparatorComponent, SuffixTemplateDirective, TemplateContextDirective, ToggleButtonTabStopDirective, WatermarkOverlayComponent, anyChanged, applyAttributes, areObjectsEqual, closest, closestBySelector, closestInScope, contains, findElement, findFocusable, findFocusableChild, firefoxMaxHeight, focusableSelector, getLicenseMessage, getter, guid, hasClasses, hasObservers, isChanged, isControlRequired, isDocumentAvailable, isFirefox, isFocusable, isFocusableWithTabKey, isObject, isObjectPresent, isPresent, isSafari, isString, isVisible, matchesClasses, matchesNodeName, normalizeNumpadKeys, parseAttributes, parseCSSClassNames, processCssValue, removeHTMLAttributes, replaceMessagePlaceholder, rtlScrollPosition, scrollbarWidth, setHTMLAttributes, setter, shouldShowValidationUI, splitStringToArray };
1789
+ export { DraggableDirective, EventsOutsideAngularDirective, KENDO_ADORNMENTS, KENDO_COMMON, KENDO_DRAGGABLE, KENDO_EVENTS, KENDO_RESIZESENSOR, KENDO_TEMPLATE_CONTEXT, KENDO_TOGGLEBUTTONTABSTOP, KENDO_WATERMARK, KendoInput, Keys, MultiTabStop, PrefixTemplateDirective, PreventableEvent, ResizeBatchService, ResizeCompatService, ResizeObserverService, ResizeSensorComponent, ScrollbarWidthService, SeparatorComponent, SuffixTemplateDirective, TemplateContextDirective, ToggleButtonTabStopDirective, WatermarkOverlayComponent, anyChanged, applyAttributes, areObjectsEqual, closest, closestBySelector, closestInScope, contains, findElement, findFocusable, findFocusableChild, firefoxMaxHeight, focusableSelector, getLicenseMessage, getter, guid, hasClasses, hasObservers, isChanged, isControlRequired, isDocumentAvailable, isFirefox, isFocusable, isFocusableWithTabKey, isObject, isObjectPresent, isPresent, isSafari, isString, isVisible, matchesClasses, matchesNodeName, normalizeKeys, parseAttributes, parseCSSClassNames, processCssValue, removeHTMLAttributes, replaceMessagePlaceholder, rtlScrollPosition, scrollbarWidth, setHTMLAttributes, setter, shouldShowValidationUI, splitStringToArray };
1727
1790
 
package/index.d.ts CHANGED
@@ -11,7 +11,7 @@ export * from './utils';
11
11
  export * from './enums';
12
12
  export * from './utils/focusable-selectors';
13
13
  export * from './utils/ng-class-parser';
14
- export * from './utils/numpad-keys-normalizer';
14
+ export * from './utils/keys-normalizer';
15
15
  export * from './utils/getter';
16
16
  export * from './utils/setter';
17
17
  export * from './watermark';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@progress/kendo-angular-common",
3
- "version": "21.1.1-develop.2",
3
+ "version": "21.2.0-develop.10",
4
4
  "description": "Kendo UI for Angular - Utility Package",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "Progress",
@@ -23,7 +23,7 @@
23
23
  "@progress/kendo-common": "^1.0.1",
24
24
  "@progress/kendo-draggable": "^3.0.2",
25
25
  "tslib": "^2.3.1",
26
- "@progress/kendo-angular-schematics": "21.1.1-develop.2"
26
+ "@progress/kendo-angular-schematics": "21.2.0-develop.10"
27
27
  },
28
28
  "publishConfig": {
29
29
  "access": "public"
@@ -0,0 +1,23 @@
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
+ /**
6
+ * @hidden
7
+ *
8
+ * Normalizes keyboard events to ensure consistent key handling across different keyboard layouts.
9
+ *
10
+ * This function addresses the following scenarios:
11
+ * 1. On some keyboards, PageUp/Down, Home/End, and arrow keys are mapped to Numpad keys
12
+ * 2. For letter keys (KeyA-KeyZ), checks the deprecated keyCode property to handle non-QWERTY layouts
13
+ * (e.g., AZERTY, QWERTZ) where event.code may not match the expected letter
14
+ *
15
+ * @param event - The keyboard event to normalize
16
+ * @returns The normalized key code string (e.g., 'KeyA', 'ArrowDown', 'Enter')
17
+ *
18
+ * @example
19
+ * // On an AZERTY layout, pressing Ctrl+A (where 'A' is physically at 'Q' position)
20
+ * // event.code = 'KeyQ', event.keyCode = 65
21
+ * const code = normalizeKeys(event); // Returns 'KeyA'
22
+ */
23
+ export declare const normalizeKeys: (event: KeyboardEvent) => string;
@@ -1,40 +0,0 @@
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
- import { Keys } from "../enums";
6
- /**
7
- * @hidden
8
- *
9
- * On some keyboards, PageUp/Down, Home/End, and arrow keys are mapped to Numpad keys
10
- */
11
- export const normalizeNumpadKeys = (event) => {
12
- if (event.code === Keys.Numpad1 && event.key === Keys.End) {
13
- return Keys.End;
14
- }
15
- if (event.code === Keys.Numpad2 && event.key === Keys.ArrowDown) {
16
- return Keys.ArrowDown;
17
- }
18
- if (event.code === Keys.Numpad3 && event.key === Keys.PageDown) {
19
- return Keys.PageDown;
20
- }
21
- if (event.code === Keys.Numpad4 && event.key === Keys.ArrowLeft) {
22
- return Keys.ArrowLeft;
23
- }
24
- if (event.code === Keys.Numpad6 && event.key === Keys.ArrowRight) {
25
- return Keys.ArrowRight;
26
- }
27
- if (event.code === Keys.Numpad7 && event.key === Keys.Home) {
28
- return Keys.Home;
29
- }
30
- if (event.code === Keys.Numpad8 && event.key === Keys.ArrowUp) {
31
- return Keys.ArrowUp;
32
- }
33
- if (event.code === Keys.Numpad9 && event.key === Keys.PageUp) {
34
- return Keys.PageUp;
35
- }
36
- if (event.code === Keys.NumpadEnter) {
37
- return Keys.Enter;
38
- }
39
- return event.code;
40
- };
@@ -1,10 +0,0 @@
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
- /**
6
- * @hidden
7
- *
8
- * On some keyboards, PageUp/Down, Home/End, and arrow keys are mapped to Numpad keys
9
- */
10
- export declare const normalizeNumpadKeys: (event: KeyboardEvent) => string;