@progress/kendo-angular-common 16.4.0-develop.4 → 16.4.0-develop.6

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.
@@ -5,7 +5,7 @@
5
5
  import { TemplateRef } from '@angular/core';
6
6
  import * as i0 from "@angular/core";
7
7
  /**
8
- * Specifies the adornments in the prefix container of the [Inputs]({% slug adornments_textbox %}#toc-prefixadornments) and [DropDowns]({% slug adornments_multiselect %}#toc-prefixadornments).
8
+ * Specifies the adornments in the prefix container of the [Inputs](slug:adornments_textbox#toc-prefix-adornments) and [DropDowns](slug:adornments_multiselect#toc-prefix-adornments).
9
9
  * ```ts-no-run
10
10
  * _@Component({
11
11
  * selector: 'my-app',
@@ -5,7 +5,7 @@
5
5
  import { TemplateRef } from '@angular/core';
6
6
  import * as i0 from "@angular/core";
7
7
  /**
8
- * Specifies the adornments in the suffix container of the [Inputs]({% slug adornments_textbox %}#toc-suffixadornments) and [DropDowns]({% slug adornments_multiselect %}#toc-suffixadornments).
8
+ * Specifies the adornments in the suffix container of the [Inputs](slug:adornments_textbox#toc-suffix-adornments) and [DropDowns](slug:adornments_multiselect#toc-suffix-adornments).
9
9
  * ```ts-no-run
10
10
  * _@Component({
11
11
  * selector: 'my-app',
@@ -5,7 +5,7 @@
5
5
  import { Directive, Input, Optional, TemplateRef } from '@angular/core';
6
6
  import * as i0 from "@angular/core";
7
7
  /**
8
- * Specifies the adornments in the prefix container of the [Inputs]({% slug adornments_textbox %}#toc-prefixadornments) and [DropDowns]({% slug adornments_multiselect %}#toc-prefixadornments).
8
+ * Specifies the adornments in the prefix container of the [Inputs](slug:adornments_textbox#toc-prefix-adornments) and [DropDowns](slug:adornments_multiselect#toc-prefix-adornments).
9
9
  * ```ts-no-run
10
10
  * _@Component({
11
11
  * selector: 'my-app',
@@ -5,7 +5,7 @@
5
5
  import { Directive, Input, Optional, TemplateRef } from '@angular/core';
6
6
  import * as i0 from "@angular/core";
7
7
  /**
8
- * Specifies the adornments in the suffix container of the [Inputs]({% slug adornments_textbox %}#toc-suffixadornments) and [DropDowns]({% slug adornments_multiselect %}#toc-suffixadornments).
8
+ * Specifies the adornments in the suffix container of the [Inputs](slug:adornments_textbox#toc-suffix-adornments) and [DropDowns](slug:adornments_multiselect#toc-suffix-adornments).
9
9
  * ```ts-no-run
10
10
  * _@Component({
11
11
  * selector: 'my-app',
@@ -57,6 +57,13 @@ export class ToggleButtonTabStopDirective {
57
57
  const isClick = e instanceof PointerEvent;
58
58
  (splitButtonToggleEnter || isClick) && (this.focusButton = true);
59
59
  };
60
+ this.onKeyDown = (e) => {
61
+ if (e.keyCode === Keys.ArrowDown && e.altKey) {
62
+ e.stopImmediatePropagation();
63
+ this.focusButton = true;
64
+ this.button.click();
65
+ }
66
+ };
60
67
  if (isDevMode() && tags.indexOf(hostEl.nativeElement.tagName.toLowerCase()) === -1) {
61
68
  console.warn(`The kendoToggleButtonTabStop directive can be applied to the following components only: ${tags}`);
62
69
  }
@@ -74,23 +81,29 @@ export class ToggleButtonTabStopDirective {
74
81
  }
75
82
  if (this.hostComponent?.escape instanceof EventEmitter) {
76
83
  this.sub = this.hostComponent?.escape.subscribe(() => {
77
- if (this.isSplitButton) {
84
+ this.returnFocusToToggleButton();
85
+ });
86
+ // Returns the focus to the toggle button when component is opened through it, and the Popup is closed
87
+ // while the active element is within the component or popup.
88
+ this.sub.add(this.hostComponent.close.subscribe((e) => {
89
+ if (!e.isDefaultPrevented() && this.focusButton) {
78
90
  this.zone.onStable.pipe(take(1)).subscribe(() => {
79
- this.focusToggleButton();
91
+ this.zone.runOutsideAngular(() => {
92
+ setTimeout(() => this.focusButton = false);
93
+ });
80
94
  });
95
+ const mainFocusableElement = this.hostEl.nativeElement.querySelector('.k-split-button > .k-button:first-child, .k-input-inner');
96
+ const optionsListContainer = document.getElementById(`${mainFocusableElement.getAttribute('aria-controls')}`);
97
+ const inList = !!optionsListContainer && optionsListContainer.contains(document.activeElement);
98
+ const inWrapper = this.hostEl.nativeElement.contains(document.activeElement);
99
+ const focusInComponent = inList || inWrapper;
100
+ if (focusInComponent) {
101
+ this.returnFocusToToggleButton();
102
+ }
81
103
  }
82
- else {
83
- this.focusToggleButton();
84
- }
85
- });
86
- this.sub.add(this.hostComponent.close.subscribe(() => {
87
- this.zone.onStable.pipe(take(1)).subscribe(() => {
88
- this.zone.runOutsideAngular(() => {
89
- setTimeout(() => this.focusButton = false);
90
- });
91
- });
92
104
  }));
93
105
  }
106
+ const close = this.hostComponent.close;
94
107
  }
95
108
  ngOnChanges(changes) {
96
109
  if (!isDocumentAvailable()) {
@@ -114,6 +127,9 @@ export class ToggleButtonTabStopDirective {
114
127
  this.button && this.renderer.setAttribute(this.button, 'tabindex', tabindex);
115
128
  this.button && this.renderer.setAttribute(this.button, 'aria-label', this.toggleButtonAriaLabel);
116
129
  this.button && this.renderer.removeAttribute(this.button, 'aria-hidden');
130
+ if (!this.observer) {
131
+ this.initializeObserver(el);
132
+ }
117
133
  this.removeListeners();
118
134
  this.addListeners();
119
135
  }
@@ -122,6 +138,8 @@ export class ToggleButtonTabStopDirective {
122
138
  this.button && this.renderer.setAttribute(this.button, 'aria-hidden', 'true');
123
139
  this.button && this.renderer.removeAttribute(this.button, 'aria-label');
124
140
  this.removeListeners();
141
+ this.observer && this.observer.disconnect();
142
+ this.observer = null;
125
143
  }
126
144
  addListeners() {
127
145
  if (this.button) {
@@ -129,6 +147,7 @@ export class ToggleButtonTabStopDirective {
129
147
  this.zone.runOutsideAngular(() => this.button.addEventListener('blur', this.onBlur));
130
148
  this.zone.runOutsideAngular(() => this.button.addEventListener('click', this.onClick));
131
149
  this.isSplitButton && this.zone.runOutsideAngular(() => this.button.addEventListener('keyup', this.onClick));
150
+ this.zone.runOutsideAngular(() => this.button.addEventListener('keydown', this.onKeyDown, true));
132
151
  }
133
152
  }
134
153
  removeListeners() {
@@ -137,12 +156,48 @@ export class ToggleButtonTabStopDirective {
137
156
  this.zone.runOutsideAngular(() => this.button.removeEventListener('blur', this.onBlur));
138
157
  this.zone.runOutsideAngular(() => this.button.removeEventListener('click', this.onClick));
139
158
  this.isSplitButton && this.zone.runOutsideAngular(() => this.button.removeEventListener('keyup', this.onClick));
159
+ this.zone.runOutsideAngular(() => this.button.removeEventListener('keydown', this.onKeyDown));
140
160
  }
141
161
  }
142
162
  focusToggleButton() {
143
163
  this.focusButton && this.zone.runOutsideAngular(() => this.button.focus());
144
164
  this.focusButton = false;
145
165
  }
166
+ returnFocusToToggleButton() {
167
+ if (this.isSplitButton) {
168
+ this.zone.onStable.pipe(take(1)).subscribe(() => {
169
+ this.focusToggleButton();
170
+ });
171
+ }
172
+ else {
173
+ this.focusToggleButton();
174
+ }
175
+ }
176
+ // Keeps the `aria-controls` and `aria-expanded` attributes of the main focusable element of the component
177
+ // and the toggle button element in sync.
178
+ initializeObserver(element) {
179
+ const mainFocusableElement = element.querySelector('.k-split-button > .k-button:first-child, .k-input-inner');
180
+ const initialExpanded = mainFocusableElement.getAttribute('aria-expanded');
181
+ const initialControls = mainFocusableElement.getAttribute('aria-controls');
182
+ this.button && this.renderer.setAttribute(this.button, 'aria-expanded', initialExpanded);
183
+ this.button && initialControls && this.renderer.setAttribute(this.button, 'aria-controls', initialControls);
184
+ this.zone.runOutsideAngular(() => {
185
+ const mutationConfig = { attributes: true };
186
+ const callback = (mutationList) => {
187
+ for (const mutation of mutationList) {
188
+ if (mutation.attributeName === 'aria-expanded') {
189
+ this.renderer.setAttribute(this.button, 'aria-expanded', mainFocusableElement.getAttribute('aria-expanded'));
190
+ }
191
+ else if (mutation.attributeName === 'aria-controls') {
192
+ const controlsRef = mainFocusableElement.getAttribute('aria-controls');
193
+ !this.isSplitButton && controlsRef ? this.renderer.setAttribute(this.button, 'aria-controls', controlsRef) : this.renderer.removeAttribute(this.button, 'aria-controls');
194
+ }
195
+ }
196
+ };
197
+ this.observer = new MutationObserver(callback);
198
+ this.observer.observe(mainFocusableElement, mutationConfig);
199
+ });
200
+ }
146
201
  }
147
202
  ToggleButtonTabStopDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ToggleButtonTabStopDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: i1.MultiTabStop }], target: i0.ɵɵFactoryTarget.Directive });
148
203
  ToggleButtonTabStopDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.10", type: ToggleButtonTabStopDirective, selector: "[kendoToggleButtonTabStop]", inputs: { active: ["kendoToggleButtonTabStop", "active"], toggleButtonAriaLabel: "toggleButtonAriaLabel" }, usesOnChanges: true, ngImport: i0 });
@@ -1044,7 +1044,7 @@ function shouldShowValidationUI(isPackageValid) {
1044
1044
  }
1045
1045
 
1046
1046
  /**
1047
- * Specifies the adornments in the prefix container of the [Inputs]({% slug adornments_textbox %}#toc-prefixadornments) and [DropDowns]({% slug adornments_multiselect %}#toc-prefixadornments).
1047
+ * Specifies the adornments in the prefix container of the [Inputs](slug:adornments_textbox#toc-prefix-adornments) and [DropDowns](slug:adornments_multiselect#toc-prefix-adornments).
1048
1048
  * ```ts-no-run
1049
1049
  * _@Component({
1050
1050
  * selector: 'my-app',
@@ -1098,7 +1098,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
1098
1098
  }] } });
1099
1099
 
1100
1100
  /**
1101
- * Specifies the adornments in the suffix container of the [Inputs]({% slug adornments_textbox %}#toc-suffixadornments) and [DropDowns]({% slug adornments_multiselect %}#toc-suffixadornments).
1101
+ * Specifies the adornments in the suffix container of the [Inputs](slug:adornments_textbox#toc-suffix-adornments) and [DropDowns](slug:adornments_multiselect#toc-suffix-adornments).
1102
1102
  * ```ts-no-run
1103
1103
  * _@Component({
1104
1104
  * selector: 'my-app',
@@ -1335,6 +1335,13 @@ class ToggleButtonTabStopDirective {
1335
1335
  const isClick = e instanceof PointerEvent;
1336
1336
  (splitButtonToggleEnter || isClick) && (this.focusButton = true);
1337
1337
  };
1338
+ this.onKeyDown = (e) => {
1339
+ if (e.keyCode === Keys.ArrowDown && e.altKey) {
1340
+ e.stopImmediatePropagation();
1341
+ this.focusButton = true;
1342
+ this.button.click();
1343
+ }
1344
+ };
1338
1345
  if (isDevMode() && tags.indexOf(hostEl.nativeElement.tagName.toLowerCase()) === -1) {
1339
1346
  console.warn(`The kendoToggleButtonTabStop directive can be applied to the following components only: ${tags}`);
1340
1347
  }
@@ -1353,23 +1360,29 @@ class ToggleButtonTabStopDirective {
1353
1360
  }
1354
1361
  if (((_a = this.hostComponent) === null || _a === void 0 ? void 0 : _a.escape) instanceof EventEmitter) {
1355
1362
  this.sub = (_b = this.hostComponent) === null || _b === void 0 ? void 0 : _b.escape.subscribe(() => {
1356
- if (this.isSplitButton) {
1363
+ this.returnFocusToToggleButton();
1364
+ });
1365
+ // Returns the focus to the toggle button when component is opened through it, and the Popup is closed
1366
+ // while the active element is within the component or popup.
1367
+ this.sub.add(this.hostComponent.close.subscribe((e) => {
1368
+ if (!e.isDefaultPrevented() && this.focusButton) {
1357
1369
  this.zone.onStable.pipe(take(1)).subscribe(() => {
1358
- this.focusToggleButton();
1370
+ this.zone.runOutsideAngular(() => {
1371
+ setTimeout(() => this.focusButton = false);
1372
+ });
1359
1373
  });
1374
+ const mainFocusableElement = this.hostEl.nativeElement.querySelector('.k-split-button > .k-button:first-child, .k-input-inner');
1375
+ const optionsListContainer = document.getElementById(`${mainFocusableElement.getAttribute('aria-controls')}`);
1376
+ const inList = !!optionsListContainer && optionsListContainer.contains(document.activeElement);
1377
+ const inWrapper = this.hostEl.nativeElement.contains(document.activeElement);
1378
+ const focusInComponent = inList || inWrapper;
1379
+ if (focusInComponent) {
1380
+ this.returnFocusToToggleButton();
1381
+ }
1360
1382
  }
1361
- else {
1362
- this.focusToggleButton();
1363
- }
1364
- });
1365
- this.sub.add(this.hostComponent.close.subscribe(() => {
1366
- this.zone.onStable.pipe(take(1)).subscribe(() => {
1367
- this.zone.runOutsideAngular(() => {
1368
- setTimeout(() => this.focusButton = false);
1369
- });
1370
- });
1371
1383
  }));
1372
1384
  }
1385
+ const close = this.hostComponent.close;
1373
1386
  }
1374
1387
  ngOnChanges(changes) {
1375
1388
  if (!isDocumentAvailable()) {
@@ -1394,6 +1407,9 @@ class ToggleButtonTabStopDirective {
1394
1407
  this.button && this.renderer.setAttribute(this.button, 'tabindex', tabindex);
1395
1408
  this.button && this.renderer.setAttribute(this.button, 'aria-label', this.toggleButtonAriaLabel);
1396
1409
  this.button && this.renderer.removeAttribute(this.button, 'aria-hidden');
1410
+ if (!this.observer) {
1411
+ this.initializeObserver(el);
1412
+ }
1397
1413
  this.removeListeners();
1398
1414
  this.addListeners();
1399
1415
  }
@@ -1402,6 +1418,8 @@ class ToggleButtonTabStopDirective {
1402
1418
  this.button && this.renderer.setAttribute(this.button, 'aria-hidden', 'true');
1403
1419
  this.button && this.renderer.removeAttribute(this.button, 'aria-label');
1404
1420
  this.removeListeners();
1421
+ this.observer && this.observer.disconnect();
1422
+ this.observer = null;
1405
1423
  }
1406
1424
  addListeners() {
1407
1425
  if (this.button) {
@@ -1409,6 +1427,7 @@ class ToggleButtonTabStopDirective {
1409
1427
  this.zone.runOutsideAngular(() => this.button.addEventListener('blur', this.onBlur));
1410
1428
  this.zone.runOutsideAngular(() => this.button.addEventListener('click', this.onClick));
1411
1429
  this.isSplitButton && this.zone.runOutsideAngular(() => this.button.addEventListener('keyup', this.onClick));
1430
+ this.zone.runOutsideAngular(() => this.button.addEventListener('keydown', this.onKeyDown, true));
1412
1431
  }
1413
1432
  }
1414
1433
  removeListeners() {
@@ -1417,12 +1436,48 @@ class ToggleButtonTabStopDirective {
1417
1436
  this.zone.runOutsideAngular(() => this.button.removeEventListener('blur', this.onBlur));
1418
1437
  this.zone.runOutsideAngular(() => this.button.removeEventListener('click', this.onClick));
1419
1438
  this.isSplitButton && this.zone.runOutsideAngular(() => this.button.removeEventListener('keyup', this.onClick));
1439
+ this.zone.runOutsideAngular(() => this.button.removeEventListener('keydown', this.onKeyDown));
1420
1440
  }
1421
1441
  }
1422
1442
  focusToggleButton() {
1423
1443
  this.focusButton && this.zone.runOutsideAngular(() => this.button.focus());
1424
1444
  this.focusButton = false;
1425
1445
  }
1446
+ returnFocusToToggleButton() {
1447
+ if (this.isSplitButton) {
1448
+ this.zone.onStable.pipe(take(1)).subscribe(() => {
1449
+ this.focusToggleButton();
1450
+ });
1451
+ }
1452
+ else {
1453
+ this.focusToggleButton();
1454
+ }
1455
+ }
1456
+ // Keeps the `aria-controls` and `aria-expanded` attributes of the main focusable element of the component
1457
+ // and the toggle button element in sync.
1458
+ initializeObserver(element) {
1459
+ const mainFocusableElement = element.querySelector('.k-split-button > .k-button:first-child, .k-input-inner');
1460
+ const initialExpanded = mainFocusableElement.getAttribute('aria-expanded');
1461
+ const initialControls = mainFocusableElement.getAttribute('aria-controls');
1462
+ this.button && this.renderer.setAttribute(this.button, 'aria-expanded', initialExpanded);
1463
+ this.button && initialControls && this.renderer.setAttribute(this.button, 'aria-controls', initialControls);
1464
+ this.zone.runOutsideAngular(() => {
1465
+ const mutationConfig = { attributes: true };
1466
+ const callback = (mutationList) => {
1467
+ for (const mutation of mutationList) {
1468
+ if (mutation.attributeName === 'aria-expanded') {
1469
+ this.renderer.setAttribute(this.button, 'aria-expanded', mainFocusableElement.getAttribute('aria-expanded'));
1470
+ }
1471
+ else if (mutation.attributeName === 'aria-controls') {
1472
+ const controlsRef = mainFocusableElement.getAttribute('aria-controls');
1473
+ !this.isSplitButton && controlsRef ? this.renderer.setAttribute(this.button, 'aria-controls', controlsRef) : this.renderer.removeAttribute(this.button, 'aria-controls');
1474
+ }
1475
+ }
1476
+ };
1477
+ this.observer = new MutationObserver(callback);
1478
+ this.observer.observe(mainFocusableElement, mutationConfig);
1479
+ });
1480
+ }
1426
1481
  }
1427
1482
  ToggleButtonTabStopDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ToggleButtonTabStopDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: MultiTabStop }], target: i0.ɵɵFactoryTarget.Directive });
1428
1483
  ToggleButtonTabStopDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.10", type: ToggleButtonTabStopDirective, selector: "[kendoToggleButtonTabStop]", inputs: { active: ["kendoToggleButtonTabStop", "active"], toggleButtonAriaLabel: "toggleButtonAriaLabel" }, usesOnChanges: true, ngImport: i0 });
@@ -1039,7 +1039,7 @@ function shouldShowValidationUI(isPackageValid) {
1039
1039
  }
1040
1040
 
1041
1041
  /**
1042
- * Specifies the adornments in the prefix container of the [Inputs]({% slug adornments_textbox %}#toc-prefixadornments) and [DropDowns]({% slug adornments_multiselect %}#toc-prefixadornments).
1042
+ * Specifies the adornments in the prefix container of the [Inputs](slug:adornments_textbox#toc-prefix-adornments) and [DropDowns](slug:adornments_multiselect#toc-prefix-adornments).
1043
1043
  * ```ts-no-run
1044
1044
  * _@Component({
1045
1045
  * selector: 'my-app',
@@ -1091,7 +1091,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
1091
1091
  }] } });
1092
1092
 
1093
1093
  /**
1094
- * Specifies the adornments in the suffix container of the [Inputs]({% slug adornments_textbox %}#toc-suffixadornments) and [DropDowns]({% slug adornments_multiselect %}#toc-suffixadornments).
1094
+ * Specifies the adornments in the suffix container of the [Inputs](slug:adornments_textbox#toc-suffix-adornments) and [DropDowns](slug:adornments_multiselect#toc-suffix-adornments).
1095
1095
  * ```ts-no-run
1096
1096
  * _@Component({
1097
1097
  * selector: 'my-app',
@@ -1326,6 +1326,13 @@ class ToggleButtonTabStopDirective {
1326
1326
  const isClick = e instanceof PointerEvent;
1327
1327
  (splitButtonToggleEnter || isClick) && (this.focusButton = true);
1328
1328
  };
1329
+ this.onKeyDown = (e) => {
1330
+ if (e.keyCode === Keys.ArrowDown && e.altKey) {
1331
+ e.stopImmediatePropagation();
1332
+ this.focusButton = true;
1333
+ this.button.click();
1334
+ }
1335
+ };
1329
1336
  if (isDevMode() && tags.indexOf(hostEl.nativeElement.tagName.toLowerCase()) === -1) {
1330
1337
  console.warn(`The kendoToggleButtonTabStop directive can be applied to the following components only: ${tags}`);
1331
1338
  }
@@ -1343,23 +1350,29 @@ class ToggleButtonTabStopDirective {
1343
1350
  }
1344
1351
  if (this.hostComponent?.escape instanceof EventEmitter) {
1345
1352
  this.sub = this.hostComponent?.escape.subscribe(() => {
1346
- if (this.isSplitButton) {
1353
+ this.returnFocusToToggleButton();
1354
+ });
1355
+ // Returns the focus to the toggle button when component is opened through it, and the Popup is closed
1356
+ // while the active element is within the component or popup.
1357
+ this.sub.add(this.hostComponent.close.subscribe((e) => {
1358
+ if (!e.isDefaultPrevented() && this.focusButton) {
1347
1359
  this.zone.onStable.pipe(take(1)).subscribe(() => {
1348
- this.focusToggleButton();
1360
+ this.zone.runOutsideAngular(() => {
1361
+ setTimeout(() => this.focusButton = false);
1362
+ });
1349
1363
  });
1364
+ const mainFocusableElement = this.hostEl.nativeElement.querySelector('.k-split-button > .k-button:first-child, .k-input-inner');
1365
+ const optionsListContainer = document.getElementById(`${mainFocusableElement.getAttribute('aria-controls')}`);
1366
+ const inList = !!optionsListContainer && optionsListContainer.contains(document.activeElement);
1367
+ const inWrapper = this.hostEl.nativeElement.contains(document.activeElement);
1368
+ const focusInComponent = inList || inWrapper;
1369
+ if (focusInComponent) {
1370
+ this.returnFocusToToggleButton();
1371
+ }
1350
1372
  }
1351
- else {
1352
- this.focusToggleButton();
1353
- }
1354
- });
1355
- this.sub.add(this.hostComponent.close.subscribe(() => {
1356
- this.zone.onStable.pipe(take(1)).subscribe(() => {
1357
- this.zone.runOutsideAngular(() => {
1358
- setTimeout(() => this.focusButton = false);
1359
- });
1360
- });
1361
1373
  }));
1362
1374
  }
1375
+ const close = this.hostComponent.close;
1363
1376
  }
1364
1377
  ngOnChanges(changes) {
1365
1378
  if (!isDocumentAvailable()) {
@@ -1383,6 +1396,9 @@ class ToggleButtonTabStopDirective {
1383
1396
  this.button && this.renderer.setAttribute(this.button, 'tabindex', tabindex);
1384
1397
  this.button && this.renderer.setAttribute(this.button, 'aria-label', this.toggleButtonAriaLabel);
1385
1398
  this.button && this.renderer.removeAttribute(this.button, 'aria-hidden');
1399
+ if (!this.observer) {
1400
+ this.initializeObserver(el);
1401
+ }
1386
1402
  this.removeListeners();
1387
1403
  this.addListeners();
1388
1404
  }
@@ -1391,6 +1407,8 @@ class ToggleButtonTabStopDirective {
1391
1407
  this.button && this.renderer.setAttribute(this.button, 'aria-hidden', 'true');
1392
1408
  this.button && this.renderer.removeAttribute(this.button, 'aria-label');
1393
1409
  this.removeListeners();
1410
+ this.observer && this.observer.disconnect();
1411
+ this.observer = null;
1394
1412
  }
1395
1413
  addListeners() {
1396
1414
  if (this.button) {
@@ -1398,6 +1416,7 @@ class ToggleButtonTabStopDirective {
1398
1416
  this.zone.runOutsideAngular(() => this.button.addEventListener('blur', this.onBlur));
1399
1417
  this.zone.runOutsideAngular(() => this.button.addEventListener('click', this.onClick));
1400
1418
  this.isSplitButton && this.zone.runOutsideAngular(() => this.button.addEventListener('keyup', this.onClick));
1419
+ this.zone.runOutsideAngular(() => this.button.addEventListener('keydown', this.onKeyDown, true));
1401
1420
  }
1402
1421
  }
1403
1422
  removeListeners() {
@@ -1406,12 +1425,48 @@ class ToggleButtonTabStopDirective {
1406
1425
  this.zone.runOutsideAngular(() => this.button.removeEventListener('blur', this.onBlur));
1407
1426
  this.zone.runOutsideAngular(() => this.button.removeEventListener('click', this.onClick));
1408
1427
  this.isSplitButton && this.zone.runOutsideAngular(() => this.button.removeEventListener('keyup', this.onClick));
1428
+ this.zone.runOutsideAngular(() => this.button.removeEventListener('keydown', this.onKeyDown));
1409
1429
  }
1410
1430
  }
1411
1431
  focusToggleButton() {
1412
1432
  this.focusButton && this.zone.runOutsideAngular(() => this.button.focus());
1413
1433
  this.focusButton = false;
1414
1434
  }
1435
+ returnFocusToToggleButton() {
1436
+ if (this.isSplitButton) {
1437
+ this.zone.onStable.pipe(take(1)).subscribe(() => {
1438
+ this.focusToggleButton();
1439
+ });
1440
+ }
1441
+ else {
1442
+ this.focusToggleButton();
1443
+ }
1444
+ }
1445
+ // Keeps the `aria-controls` and `aria-expanded` attributes of the main focusable element of the component
1446
+ // and the toggle button element in sync.
1447
+ initializeObserver(element) {
1448
+ const mainFocusableElement = element.querySelector('.k-split-button > .k-button:first-child, .k-input-inner');
1449
+ const initialExpanded = mainFocusableElement.getAttribute('aria-expanded');
1450
+ const initialControls = mainFocusableElement.getAttribute('aria-controls');
1451
+ this.button && this.renderer.setAttribute(this.button, 'aria-expanded', initialExpanded);
1452
+ this.button && initialControls && this.renderer.setAttribute(this.button, 'aria-controls', initialControls);
1453
+ this.zone.runOutsideAngular(() => {
1454
+ const mutationConfig = { attributes: true };
1455
+ const callback = (mutationList) => {
1456
+ for (const mutation of mutationList) {
1457
+ if (mutation.attributeName === 'aria-expanded') {
1458
+ this.renderer.setAttribute(this.button, 'aria-expanded', mainFocusableElement.getAttribute('aria-expanded'));
1459
+ }
1460
+ else if (mutation.attributeName === 'aria-controls') {
1461
+ const controlsRef = mainFocusableElement.getAttribute('aria-controls');
1462
+ !this.isSplitButton && controlsRef ? this.renderer.setAttribute(this.button, 'aria-controls', controlsRef) : this.renderer.removeAttribute(this.button, 'aria-controls');
1463
+ }
1464
+ }
1465
+ };
1466
+ this.observer = new MutationObserver(callback);
1467
+ this.observer.observe(mainFocusableElement, mutationConfig);
1468
+ });
1469
+ }
1415
1470
  }
1416
1471
  ToggleButtonTabStopDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ToggleButtonTabStopDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: MultiTabStop }], target: i0.ɵɵFactoryTarget.Directive });
1417
1472
  ToggleButtonTabStopDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.10", type: ToggleButtonTabStopDirective, selector: "[kendoToggleButtonTabStop]", inputs: { active: ["kendoToggleButtonTabStop", "active"], toggleButtonAriaLabel: "toggleButtonAriaLabel" }, usesOnChanges: true, ngImport: i0 });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@progress/kendo-angular-common",
3
- "version": "16.4.0-develop.4",
3
+ "version": "16.4.0-develop.6",
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": "^0.2.1",
24
24
  "@progress/kendo-draggable": "^3.0.2",
25
25
  "tslib": "^2.3.1",
26
- "@progress/kendo-angular-schematics": "16.4.0-develop.4"
26
+ "@progress/kendo-angular-schematics": "16.4.0-develop.6"
27
27
  },
28
28
  "publishConfig": {
29
29
  "access": "public"
@@ -47,6 +47,7 @@ export declare class ToggleButtonTabStopDirective {
47
47
  private sub;
48
48
  private focusButton;
49
49
  private isSplitButton;
50
+ private observer;
50
51
  /**
51
52
  * @hidden
52
53
  */
@@ -60,9 +61,12 @@ export declare class ToggleButtonTabStopDirective {
60
61
  private onFocus;
61
62
  private onBlur;
62
63
  private onClick;
64
+ private onKeyDown;
63
65
  private addListeners;
64
66
  private removeListeners;
65
67
  private focusToggleButton;
68
+ private returnFocusToToggleButton;
69
+ private initializeObserver;
66
70
  static ɵfac: i0.ɵɵFactoryDeclaration<ToggleButtonTabStopDirective, never>;
67
71
  static ɵdir: i0.ɵɵDirectiveDeclaration<ToggleButtonTabStopDirective, "[kendoToggleButtonTabStop]", never, { "active": "kendoToggleButtonTabStop"; "toggleButtonAriaLabel": "toggleButtonAriaLabel"; }, {}, never, never, false, never>;
68
72
  }