@progress/kendo-angular-filter 2.2.3-dev.202210120943 → 2.3.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.
Files changed (33) hide show
  1. package/aria-label.directive.d.ts +1 -1
  2. package/base-filter-row.component.d.ts +28 -0
  3. package/bundles/kendo-angular-filter.umd.js +1 -1
  4. package/editors/boolean-editor.component.d.ts +1 -0
  5. package/editors/date-editor.component.d.ts +1 -0
  6. package/editors/numeric-editor.component.d.ts +1 -0
  7. package/editors/text-editor.component.d.ts +1 -0
  8. package/error-messages.d.ts +8 -0
  9. package/esm2015/aria-label.directive.js +2 -2
  10. package/esm2015/base-filter-row.component.js +69 -0
  11. package/esm2015/editors/boolean-editor.component.js +10 -4
  12. package/esm2015/editors/date-editor.component.js +10 -4
  13. package/esm2015/editors/numeric-editor.component.js +10 -4
  14. package/esm2015/editors/text-editor.component.js +10 -4
  15. package/esm2015/error-messages.js +16 -0
  16. package/esm2015/filter-expression-operators.component.js +2 -0
  17. package/esm2015/filter-expression.component.js +60 -47
  18. package/esm2015/filter-group.component.js +76 -38
  19. package/esm2015/filter.component.js +107 -32
  20. package/esm2015/filter.module.js +2 -1
  21. package/esm2015/localization/messages.js +3 -3
  22. package/esm2015/navigation.service.js +159 -0
  23. package/esm2015/package-metadata.js +1 -1
  24. package/esm2015/util.js +33 -0
  25. package/fesm2015/kendo-angular-filter.js +523 -122
  26. package/filter-expression.component.d.ts +7 -10
  27. package/filter-group.component.d.ts +11 -10
  28. package/filter.component.d.ts +24 -4
  29. package/localization/messages.d.ts +3 -3
  30. package/model/filter-expression.d.ts +1 -1
  31. package/navigation.service.d.ts +40 -0
  32. package/package.json +1 -1
  33. package/util.d.ts +12 -0
@@ -3,19 +3,20 @@
3
3
  * Licensed under commercial license. See LICENSE.md in the project root for more information
4
4
  *-------------------------------------------------------------------------------------------*/
5
5
  import * as i0 from '@angular/core';
6
- import { Injectable, Directive, Component, Input, ContentChild, EventEmitter, Output, isDevMode, forwardRef, HostBinding, ContentChildren, NgModule } from '@angular/core';
6
+ import { Injectable, Directive, Component, Input, ContentChild, EventEmitter, Output, isDevMode, forwardRef, ViewChildren, HostListener, HostBinding, ContentChildren, NgModule } from '@angular/core';
7
7
  import * as i1 from '@progress/kendo-angular-l10n';
8
8
  import { ComponentMessages, LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n';
9
9
  import { validatePackage } from '@progress/kendo-licensing';
10
+ import { Keys } from '@progress/kendo-angular-common';
10
11
  import * as i2 from '@progress/kendo-angular-dropdowns';
11
12
  import { DropDownsModule } from '@progress/kendo-angular-dropdowns';
12
13
  import * as i2$1 from '@progress/kendo-angular-inputs';
13
14
  import { InputsModule } from '@progress/kendo-angular-inputs';
14
15
  import * as i2$2 from '@progress/kendo-angular-dateinputs';
15
16
  import { DateInputsModule } from '@progress/kendo-angular-dateinputs';
16
- import * as i10 from '@angular/common';
17
+ import * as i11 from '@angular/common';
17
18
  import { CommonModule } from '@angular/common';
18
- import * as i11 from '@progress/kendo-angular-buttons';
19
+ import * as i12 from '@progress/kendo-angular-buttons';
19
20
  import { ButtonsModule } from '@progress/kendo-angular-buttons';
20
21
  import { LabelModule } from '@progress/kendo-angular-label';
21
22
 
@@ -193,6 +194,37 @@ const localizeOperators = operators => localization => Object.keys(operators).ma
193
194
  * @hidden
194
195
  */
195
196
  const isPresent = (value) => value !== null && value !== undefined;
197
+ /**
198
+ * @hidden
199
+ */
200
+ class FilterItem {
201
+ }
202
+ FilterItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterItem, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
203
+ FilterItem.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterItem });
204
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterItem, decorators: [{
205
+ type: Injectable
206
+ }] });
207
+ /**
208
+ * @hidden
209
+ */
210
+ const selectors = {
211
+ andButton: `button.k-group-start`,
212
+ orButton: `button.k-group-end`,
213
+ addFilterButton: `button[icon="filter-add-expression"]`,
214
+ addGroupButton: `button[icon="filter-add-group"]`,
215
+ removeButton: `button[icon="x"]`,
216
+ filterFieldWrapper: `.k-filter-field`,
217
+ filterOperatorWrapper: `.k-filter-operator`,
218
+ filterValueEditorWrapper: `.k-filter-value`,
219
+ kendoDropDownListComponent: `kendo-dropdownlist`,
220
+ kendoInput: `.k-input`,
221
+ kendoInputInner: `.k-input-inner`,
222
+ inputElement: `input`,
223
+ textAreaElement: `textarea`,
224
+ kendoToolbar: `.k-toolbar`,
225
+ kendoButton: `.k-button`,
226
+ kendoFilterToolbarItem: `.k-filter-toolbar-item`
227
+ };
196
228
 
197
229
  /**
198
230
  * @hidden
@@ -201,7 +233,7 @@ const packageMetadata = {
201
233
  name: '@progress/kendo-angular-filter',
202
234
  productName: 'Kendo UI for Angular',
203
235
  productCodes: ['KENDOUIANGULAR', 'KENDOUICOMPLETE'],
204
- publishDate: 1665567772,
236
+ publishDate: 1666694566,
205
237
  version: '',
206
238
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/?utm_medium=product&utm_source=kendoangular&utm_campaign=kendo-ui-angular-purchase-license-keys-warning'
207
239
  };
@@ -283,6 +315,232 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
283
315
  args: [FilterValueEditorTemplateDirective]
284
316
  }] } });
285
317
 
318
+ /**
319
+ * @hidden
320
+ */
321
+ class NavigationService {
322
+ constructor(cdr, renderer) {
323
+ this.cdr = cdr;
324
+ this.renderer = renderer;
325
+ this.hierarchicalFilterItems = [];
326
+ this.flattenFilterItems = [];
327
+ this.currentToolbarItemIndex = 0;
328
+ this.currentToolbarItemChildrenIndex = 0;
329
+ this.isInnerNavigationActivated = false;
330
+ this.isFilterExpressionComponentFocused = false;
331
+ }
332
+ processKeyDown(key, event) {
333
+ switch (key) {
334
+ case Keys.ArrowUp:
335
+ event.preventDefault();
336
+ if (!this.isInnerNavigationActivated) {
337
+ this.currentToolbarItemIndex > 0 ? this.currentToolbarItemIndex-- : this.currentToolbarItemIndex;
338
+ const elementToFocus = this.flattenFilterItems[this.currentToolbarItemIndex].toolbarElement;
339
+ this.focusCurrentElement(elementToFocus);
340
+ }
341
+ break;
342
+ case Keys.ArrowDown:
343
+ event.preventDefault();
344
+ if (!this.isInnerNavigationActivated) {
345
+ this.currentToolbarItemIndex < this.flattenFilterItems.length - 1 ? this.currentToolbarItemIndex++ : this.currentToolbarItemIndex;
346
+ const elementToFocus = this.flattenFilterItems[this.currentToolbarItemIndex].toolbarElement;
347
+ this.focusCurrentElement(elementToFocus);
348
+ }
349
+ break;
350
+ case Keys.Enter:
351
+ const isEventTargetFilterToolbar = event.target.closest(selectors.kendoToolbar);
352
+ if (!this.isInnerNavigationActivated && isEventTargetFilterToolbar) {
353
+ event.preventDefault();
354
+ this.isInnerNavigationActivated = true;
355
+ this.currentToolbarItemChildrenIndex = 0;
356
+ const elementToFocus = this.flattenFilterItems[this.currentToolbarItemIndex].focusableChildren[this.currentToolbarItemChildrenIndex];
357
+ this.focusCurrentElement(elementToFocus);
358
+ }
359
+ const isEventTargetKendoFilterToolbarItem = event.target.closest(selectors.kendoFilterToolbarItem);
360
+ const isEventTargetButton = event.target.closest(selectors.kendoButton);
361
+ if (this.isInnerNavigationActivated &&
362
+ !this.isFilterExpressionComponentFocused &&
363
+ isEventTargetKendoFilterToolbarItem &&
364
+ !isEventTargetButton) {
365
+ event.preventDefault();
366
+ this.isFilterExpressionComponentFocused = true;
367
+ const focusableElement = this.flattenFilterItems[this.currentToolbarItemIndex].focusableChildren[this.currentToolbarItemChildrenIndex];
368
+ const elementToFocus = focusableElement.querySelector(selectors.KendoDropDownListComponent) ||
369
+ focusableElement.querySelector(selectors.kendoInputInner) ||
370
+ focusableElement.querySelector(selectors.inputElement) ||
371
+ focusableElement.querySelector(selectors.textAreaElement);
372
+ this.focusCurrentElement(elementToFocus);
373
+ }
374
+ break;
375
+ case Keys.Escape:
376
+ if (this.isInnerNavigationActivated && !this.isFilterExpressionComponentFocused) {
377
+ event.preventDefault();
378
+ this.isInnerNavigationActivated = false;
379
+ this.currentToolbarItemChildrenIndex = 0;
380
+ const elementToFocus = this.flattenFilterItems[this.currentToolbarItemIndex].toolbarElement;
381
+ this.focusCurrentElement(elementToFocus);
382
+ }
383
+ if (this.isFilterExpressionComponentFocused) {
384
+ event.preventDefault();
385
+ this.isFilterExpressionComponentFocused = false;
386
+ this.isInnerNavigationActivated = true;
387
+ const elementToFocus = this.flattenFilterItems[this.currentToolbarItemIndex].focusableChildren[this.currentToolbarItemChildrenIndex];
388
+ this.focusCurrentElement(elementToFocus);
389
+ }
390
+ break;
391
+ case Keys.ArrowRight:
392
+ if (this.isInnerNavigationActivated && !this.isFilterExpressionComponentFocused) {
393
+ event.preventDefault();
394
+ this.currentToolbarItemChildrenIndex < this.flattenFilterItems[this.currentToolbarItemIndex].focusableChildren.length - 1 ? this.currentToolbarItemChildrenIndex++ : this.currentToolbarItemChildrenIndex;
395
+ const elementToFocus = this.flattenFilterItems[this.currentToolbarItemIndex].focusableChildren[this.currentToolbarItemChildrenIndex];
396
+ this.focusCurrentElement(elementToFocus);
397
+ }
398
+ break;
399
+ case Keys.ArrowLeft:
400
+ if (this.isInnerNavigationActivated && !this.isFilterExpressionComponentFocused) {
401
+ event.preventDefault();
402
+ this.currentToolbarItemChildrenIndex > 0 ? this.currentToolbarItemChildrenIndex-- : this.currentToolbarItemChildrenIndex;
403
+ const elementToFocus = this.flattenFilterItems[this.currentToolbarItemIndex].focusableChildren[this.currentToolbarItemChildrenIndex];
404
+ this.focusCurrentElement(elementToFocus);
405
+ }
406
+ break;
407
+ default:
408
+ break;
409
+ }
410
+ }
411
+ focusCurrentElement(element, isOnMouseDown) {
412
+ this.renderer.setAttribute(this.currentlyFocusedElement, 'tabindex', '-1');
413
+ this.currentlyFocusedElement = element;
414
+ if (element) {
415
+ this.renderer.setAttribute(this.currentlyFocusedElement, 'tabindex', '0');
416
+ if (!isOnMouseDown) {
417
+ this.currentlyFocusedElement.focus();
418
+ }
419
+ }
420
+ }
421
+ flattenHierarchicalFilterItems(filterItems) {
422
+ filterItems.forEach((filterRow) => {
423
+ var _a, _b;
424
+ let flattenItem = { component: filterRow, isGroup: false, toolbarElement: filterRow.toolbarElement, focusableChildren: [] };
425
+ this.flattenFilterItems.push(flattenItem);
426
+ if ((filterRow['operators'] && ((_a = filterRow['filterItems']) === null || _a === void 0 ? void 0 : _a.length) > 0)) {
427
+ this.setGroupItemChildren(flattenItem, filterRow);
428
+ this.flattenHierarchicalFilterItems(filterRow['filterItems']);
429
+ }
430
+ else if (filterRow['operators'] && ((_b = filterRow['filterItems']) === null || _b === void 0 ? void 0 : _b.length) === 0) {
431
+ this.setGroupItemChildren(flattenItem, filterRow);
432
+ }
433
+ else {
434
+ flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.filterFieldWrapper));
435
+ if (filterRow.toolbarElement.querySelector('.k-filter-operator')) {
436
+ flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.filterOperatorWrapper));
437
+ }
438
+ flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.filterValueEditorWrapper));
439
+ flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.removeButton));
440
+ }
441
+ });
442
+ }
443
+ setGroupItemChildren(flattenItem, filterRow) {
444
+ flattenItem.isGroup = true;
445
+ flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.andButton));
446
+ flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.orButton));
447
+ flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.addFilterButton));
448
+ flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.addGroupButton));
449
+ flattenItem.focusableChildren.push(filterRow.toolbarElement.querySelector(selectors.removeButton));
450
+ }
451
+ setItemIndexes() {
452
+ this.flattenFilterItems.forEach((item, index) => {
453
+ item.component['itemNumber'] = index;
454
+ });
455
+ this.cdr.detectChanges();
456
+ }
457
+ reset(items) {
458
+ this.flattenFilterItems = [];
459
+ this.hierarchicalFilterItems = items;
460
+ this.flattenHierarchicalFilterItems(items);
461
+ this.setItemIndexes();
462
+ }
463
+ }
464
+ NavigationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: NavigationService, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Injectable });
465
+ NavigationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: NavigationService });
466
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: NavigationService, decorators: [{
467
+ type: Injectable
468
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }]; } });
469
+
470
+ /**
471
+ * @hidden
472
+ */
473
+ const FilterErrorMessages = {
474
+ missingFilters: `Pass at least one user-defined filter through the [filters] input property or nest kendo-filter-field components. See http://www.telerik.com/kendo-angular-ui/components/filter/#data-binding`,
475
+ missingFilterForUsedField: (field) => `There is no user-defined filter with '${field}' field provided through the [filters] input property.`,
476
+ missingValueForBooleanField: (field) => `Provide a value for the boolean '${field}' user-defined filter as the operator is always set to 'eq'.`,
477
+ operatorBooleanField: (field) => `The operator of the boolean '${field}' user-defined filter is always set to 'eq'.`,
478
+ filterMissingUsedOperator: (field, operator) => `The user-defined filter with field '${field}' is missing the '${operator}' operator.`,
479
+ improperNumericEditorValue: (title) => `The provided value for the numeric editor of the '${title}' filter expression isn't one of a supported type string or NumberFormat. See http://www.telerik.com/kendo-angular-ui/components/filter/#editor-formats/`,
480
+ improperDateEditorValue: (title) => `The provided value for the date editor of the '${title}' filter expression isn't one of a supported type string or DateFormat. See http://www.telerik.com/kendo-angular-ui/components/filter/#editor-formats/`
481
+ };
482
+
483
+ /**
484
+ * @hidden
485
+ */
486
+ class BaseFilterRowComponent {
487
+ constructor(element, navigationService, localization, renderer) {
488
+ this.element = element;
489
+ this.navigationService = navigationService;
490
+ this.localization = localization;
491
+ this.renderer = renderer;
492
+ this.valueChange = new EventEmitter();
493
+ }
494
+ get toolbarElement() {
495
+ return this.element.nativeElement.querySelector('.k-toolbar');
496
+ }
497
+ onFocus() {
498
+ this.renderer.addClass(this.navigationService.flattenFilterItems[this.itemNumber].toolbarElement, 'k-focus');
499
+ this.navigationService.isInnerNavigationActivated = false;
500
+ }
501
+ onBlur() {
502
+ this.renderer.removeClass(this.navigationService.flattenFilterItems[this.itemNumber].toolbarElement, 'k-focus');
503
+ }
504
+ messageFor(key) {
505
+ return this.localization.get(key);
506
+ }
507
+ onMouseDown(event) {
508
+ let elementToFocus;
509
+ const closestFilterToolbarItem = event.target.closest(selectors.kendoFilterToolbarItem);
510
+ const closestToolbarItem = event.target.closest(selectors.kendoToolbar);
511
+ if (closestFilterToolbarItem) {
512
+ let index = Array.from(closestToolbarItem.children).indexOf(closestFilterToolbarItem);
513
+ this.navigationService.currentToolbarItemChildrenIndex = index;
514
+ this.navigationService.isInnerNavigationActivated = true;
515
+ this.navigationService.isFilterExpressionComponentFocused = true;
516
+ const wrapperElement = this.navigationService.flattenFilterItems[this.itemNumber].focusableChildren[index];
517
+ elementToFocus = wrapperElement.querySelector(selectors.kendoDropDownListComponent) ||
518
+ wrapperElement.querySelector(selectors.kendoInput) ||
519
+ wrapperElement.querySelector(selectors.kendoInputInner) ||
520
+ wrapperElement.querySelector(selectors.inputElement) ||
521
+ wrapperElement.querySelector(selectors.textAreaElement);
522
+ }
523
+ else {
524
+ this.navigationService.currentToolbarItemChildrenIndex = 0;
525
+ this.navigationService.isInnerNavigationActivated = false;
526
+ this.navigationService.isFilterExpressionComponentFocused = false;
527
+ elementToFocus = this.navigationService.flattenFilterItems[this.itemNumber].toolbarElement;
528
+ }
529
+ this.navigationService.currentToolbarItemIndex = this.itemNumber;
530
+ this.navigationService.focusCurrentElement(elementToFocus, true);
531
+ }
532
+ }
533
+ BaseFilterRowComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: BaseFilterRowComponent, deps: [{ token: i0.ElementRef }, { token: NavigationService }, { token: i1.LocalizationService }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
534
+ BaseFilterRowComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.16", type: BaseFilterRowComponent, inputs: { index: "index" }, outputs: { valueChange: "valueChange" }, ngImport: i0 });
535
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: BaseFilterRowComponent, decorators: [{
536
+ type: Directive,
537
+ args: [{}]
538
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: NavigationService }, { type: i1.LocalizationService }, { type: i0.Renderer2 }]; }, propDecorators: { index: [{
539
+ type: Input
540
+ }], valueChange: [{
541
+ type: Output
542
+ }] } });
543
+
286
544
  /**
287
545
  * @hidden
288
546
  */
@@ -291,13 +549,13 @@ class AriaLabelValueDirective {
291
549
  this.hostElement = hostElement;
292
550
  this.renderer = renderer;
293
551
  }
294
- ngOnChanges() {
552
+ ngOnInit() {
295
553
  const target = this.hostElement.nativeElement.querySelector('input') || this.hostElement.nativeElement;
296
554
  this.renderer.setAttribute(target, 'aria-label', this.ariaLabel);
297
555
  }
298
556
  }
299
557
  AriaLabelValueDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: AriaLabelValueDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
300
- AriaLabelValueDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.16", type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: { ariaLabel: ["kendoAriaLabelValue", "ariaLabel"] }, usesOnChanges: true, ngImport: i0 });
558
+ AriaLabelValueDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.16", type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: { ariaLabel: ["kendoAriaLabelValue", "ariaLabel"] }, ngImport: i0 });
301
559
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: AriaLabelValueDirective, decorators: [{
302
560
  type: Directive,
303
561
  args: [{ selector: '[kendoAriaLabelValue]' }]
@@ -328,6 +586,7 @@ class FilterExpressionOperatorsComponent {
328
586
  FilterExpressionOperatorsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterExpressionOperatorsComponent, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
329
587
  FilterExpressionOperatorsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterExpressionOperatorsComponent, selector: "kendo-filter-expression-operators", inputs: { currentItem: "currentItem", editorType: "editorType", operators: "operators" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
330
588
  <kendo-dropdownlist
589
+ [tabindex]="-1"
331
590
  [kendoAriaLabelValue]="messageFor('filterOperatorAriaLabel')"
332
591
  [data]="operators"
333
592
  [title]="messageFor('filterExpressionOperators')"
@@ -351,6 +610,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
351
610
  selector: "kendo-filter-expression-operators",
352
611
  template: `
353
612
  <kendo-dropdownlist
613
+ [tabindex]="-1"
354
614
  [kendoAriaLabelValue]="messageFor('filterOperatorAriaLabel')"
355
615
  [data]="operators"
356
616
  [title]="messageFor('filterExpressionOperators')"
@@ -390,13 +650,18 @@ class FilterTextEditorComponent {
390
650
  messageFor(key) {
391
651
  return this.localization.get(key);
392
652
  }
653
+ onValueChange(value) {
654
+ this.currentItem.value = value;
655
+ this.valueChange.emit();
656
+ }
393
657
  }
394
658
  FilterTextEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterTextEditorComponent, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
395
659
  FilterTextEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterTextEditorComponent, selector: "kendo-filter-text-editor", inputs: { currentItem: "currentItem", isDisabled: "isDisabled" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
396
660
  <kendo-textbox
661
+ [tabindex]="-1"
397
662
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
398
- [(value)]="currentItem.value"
399
- (valueChange)="valueChange.emit()"
663
+ [value]="currentItem.value"
664
+ (valueChange)="onValueChange($event)"
400
665
  [disabled]="isDisabled">
401
666
  </kendo-textbox>
402
667
  `, isInline: true, components: [{ type: i2$1.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "errorIcon", "clearButtonIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }], directives: [{ type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: ["kendoAriaLabelValue"] }] });
@@ -406,9 +671,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
406
671
  selector: 'kendo-filter-text-editor',
407
672
  template: `
408
673
  <kendo-textbox
674
+ [tabindex]="-1"
409
675
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
410
- [(value)]="currentItem.value"
411
- (valueChange)="valueChange.emit()"
676
+ [value]="currentItem.value"
677
+ (valueChange)="onValueChange($event)"
412
678
  [disabled]="isDisabled">
413
679
  </kendo-textbox>
414
680
  `
@@ -432,13 +698,18 @@ class FilterNumericEditorComponent {
432
698
  messageFor(key) {
433
699
  return this.localization.get(key);
434
700
  }
701
+ onValueChange(value) {
702
+ this.currentItem.value = value;
703
+ this.valueChange.emit();
704
+ }
435
705
  }
436
706
  FilterNumericEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterNumericEditorComponent, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
437
707
  FilterNumericEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterNumericEditorComponent, selector: "kendo-filter-numeric-editor", inputs: { currentItem: "currentItem", isDisabled: "isDisabled", format: "format" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
438
708
  <kendo-numerictextbox
709
+ [tabindex]="-1"
439
710
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
440
- [(value)]="currentItem.value"
441
- (valueChange)="valueChange.emit()"
711
+ [value]="currentItem.value"
712
+ (valueChange)="onValueChange($event)"
442
713
  [disabled]="isDisabled"
443
714
  [format]="format">
444
715
  <kendo-numerictextbox-messages
@@ -453,9 +724,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
453
724
  selector: 'kendo-filter-numeric-editor',
454
725
  template: `
455
726
  <kendo-numerictextbox
727
+ [tabindex]="-1"
456
728
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
457
- [(value)]="currentItem.value"
458
- (valueChange)="valueChange.emit()"
729
+ [value]="currentItem.value"
730
+ (valueChange)="onValueChange($event)"
459
731
  [disabled]="isDisabled"
460
732
  [format]="format">
461
733
  <kendo-numerictextbox-messages
@@ -510,13 +782,18 @@ class FilterBooleanEditorComponent {
510
782
  messageFor(key) {
511
783
  return this.localization.get(key);
512
784
  }
785
+ onValueChange(value) {
786
+ this.currentItem.value = value;
787
+ this.valueChange.emit();
788
+ }
513
789
  }
514
790
  FilterBooleanEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterBooleanEditorComponent, deps: [{ token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
515
791
  FilterBooleanEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterBooleanEditorComponent, selector: "kendo-filter-boolean-editor", inputs: { currentItem: "currentItem" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
516
792
  <kendo-dropdownlist
793
+ [tabindex]="-1"
517
794
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
518
- [(value)]="currentItem.value"
519
- (valueChange)="valueChange.emit()"
795
+ [value]="currentItem.value"
796
+ (valueChange)="onValueChange($event)"
520
797
  [data]="items"
521
798
  [defaultItem]="defaultItem"
522
799
  [valuePrimitive]="true"
@@ -531,9 +808,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
531
808
  selector: 'kendo-filter-boolean-editor',
532
809
  template: `
533
810
  <kendo-dropdownlist
811
+ [tabindex]="-1"
534
812
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
535
- [(value)]="currentItem.value"
536
- (valueChange)="valueChange.emit()"
813
+ [value]="currentItem.value"
814
+ (valueChange)="onValueChange($event)"
537
815
  [data]="items"
538
816
  [defaultItem]="defaultItem"
539
817
  [valuePrimitive]="true"
@@ -560,13 +838,18 @@ class FilterDateEditorComponent {
560
838
  messageFor(key) {
561
839
  return this.localization.get(key);
562
840
  }
841
+ onValueChange(value) {
842
+ this.currentItem.value = value;
843
+ this.valueChange.emit();
844
+ }
563
845
  }
564
846
  FilterDateEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterDateEditorComponent, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
565
847
  FilterDateEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterDateEditorComponent, selector: "kendo-filter-date-editor", inputs: { currentItem: "currentItem", isDisabled: "isDisabled", format: "format" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
566
848
  <kendo-datepicker
849
+ [tabindex]="-1"
567
850
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
568
- [(value)]="currentItem.value"
569
- (valueChange)="valueChange.emit()"
851
+ [value]="currentItem.value"
852
+ (valueChange)="onValueChange($event)"
570
853
  [disabled]="isDisabled"
571
854
  [format]="format">
572
855
  <kendo-datepicker-messages
@@ -581,9 +864,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
581
864
  selector: 'kendo-filter-date-editor',
582
865
  template: `
583
866
  <kendo-datepicker
867
+ [tabindex]="-1"
584
868
  [kendoAriaLabelValue]="messageFor('filterValueAriaLabel')"
585
- [(value)]="currentItem.value"
586
- (valueChange)="valueChange.emit()"
869
+ [value]="currentItem.value"
870
+ (valueChange)="onValueChange($event)"
587
871
  [disabled]="isDisabled"
588
872
  [format]="format">
589
873
  <kendo-datepicker-messages
@@ -606,12 +890,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
606
890
  /**
607
891
  * @hidden
608
892
  */
609
- class FilterExpressionComponent {
610
- constructor(filterService, localization, cdr) {
893
+ class FilterExpressionComponent extends BaseFilterRowComponent {
894
+ constructor(filterService, cdr, element, navigationService, localization, renderer) {
895
+ super(element, navigationService, localization, renderer);
611
896
  this.filterService = filterService;
612
- this.localization = localization;
613
897
  this.cdr = cdr;
614
- this.valueChange = new EventEmitter();
615
898
  this.operators = [];
616
899
  this.filters = [];
617
900
  this.isBoolean = false;
@@ -621,19 +904,21 @@ class FilterExpressionComponent {
621
904
  return this.getFilterExpressionByField(this.currentItem.field);
622
905
  }
623
906
  get numericEditorFormat() {
624
- if (this.editorFormat && !this.isNumberFormat(this.editorFormat)) {
625
- console.warn(`The provided value for the numeric editor of the '${this.currentFilterExpression.title}' filter expression isn't one of a supported type string or NumberFormat. See http://www.telerik.com/kendo-angular-ui/components/filter/#editor-formats/`);
907
+ const isSupportedFormat = typeof this.editorFormat !== 'string' && !this.isNumberFormat(this.editorFormat);
908
+ if (this.editorFormat && isSupportedFormat) {
909
+ console.warn(FilterErrorMessages.improperNumericEditorValue(this.currentFilterExpression.title));
626
910
  }
627
911
  return this.editorFormat;
628
912
  }
629
913
  get dateEditorFormat() {
630
- if (this.editorFormat && !this.isDateFormat(this.editorFormat)) {
631
- console.warn(`The provided value for the date editor of the '${this.currentFilterExpression.title}' filter expression isn't one of a supported type string or DateFormat. See http://www.telerik.com/kendo-angular-ui/components/filter/#editor-formats/`);
914
+ const isSupportedFormat = typeof this.editorFormat !== 'string' && !this.isDateFormat(this.editorFormat);
915
+ if (this.editorFormat && isSupportedFormat) {
916
+ console.warn(FilterErrorMessages.improperDateEditorValue(this.currentFilterExpression.title));
632
917
  }
633
918
  return this.editorFormat;
634
919
  }
635
920
  isNumberFormat(obj) {
636
- if (isDevMode() && obj && typeof this.editorFormat !== 'string' &&
921
+ if (isDevMode() && obj &&
637
922
  (obj['currency'] ||
638
923
  obj['currencyDisplay'] ||
639
924
  obj['maximumFractionDigits'] ||
@@ -647,7 +932,7 @@ class FilterExpressionComponent {
647
932
  }
648
933
  }
649
934
  isDateFormat(obj) {
650
- if (isDevMode() && obj && typeof this.editorFormat !== 'string' && obj['displayFormat'] && obj['inputFormat']) {
935
+ if (isDevMode() && obj && obj['displayFormat'] && obj['inputFormat']) {
651
936
  return true;
652
937
  }
653
938
  else {
@@ -692,9 +977,6 @@ class FilterExpressionComponent {
692
977
  }
693
978
  return result;
694
979
  }
695
- messageFor(key) {
696
- return this.localization.get(key);
697
- }
698
980
  getFilterExpressionByField(name) {
699
981
  const foundFilter = this.filterService.filters.find(filter => filter.field === name);
700
982
  if (foundFilter) {
@@ -703,11 +985,14 @@ class FilterExpressionComponent {
703
985
  return null;
704
986
  }
705
987
  filterValueChange(value) {
988
+ this.navigationService.currentToolbarItemIndex = this.itemNumber;
989
+ this.navigationService.currentToolbarItemChildrenIndex = 0;
706
990
  this.currentItem.value = null;
707
991
  this.currentItem.field = value;
708
992
  this.setEditorTemplate();
709
993
  const foundFilter = this.getFilterExpressionByField(this.currentItem.field);
710
994
  this.setOperators(foundFilter);
995
+ this.editorFormat = foundFilter.editorFormat;
711
996
  this.valueChange.emit();
712
997
  }
713
998
  getDefaultOperators(operatorsType) {
@@ -728,7 +1013,7 @@ class FilterExpressionComponent {
728
1013
  }
729
1014
  removeFilterExpression() {
730
1015
  this.filterService.remove(this.currentItem, this.index);
731
- this.valueChange.emit();
1016
+ this.valueChange.emit(true);
732
1017
  }
733
1018
  setOperators(filter) {
734
1019
  this.isBoolean = filter.editor === 'boolean';
@@ -751,8 +1036,10 @@ class FilterExpressionComponent {
751
1036
  }
752
1037
  }
753
1038
  onOperatorChange(value) {
1039
+ this.navigationService.currentToolbarItemIndex = this.itemNumber;
1040
+ this.navigationService.currentToolbarItemChildrenIndex = 1;
754
1041
  this.valueChange.emit();
755
- if (nullOperators.indexOf(value) >= 0) {
1042
+ if (nullOperators.includes(value)) {
756
1043
  this.currentItem.value = null;
757
1044
  this.isEditorDisabled = true;
758
1045
  }
@@ -765,12 +1052,16 @@ class FilterExpressionComponent {
765
1052
  this.editorTemplate = filterExpression.editorTemplate ? filterExpression.editorTemplate : null;
766
1053
  }
767
1054
  }
768
- FilterExpressionComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterExpressionComponent, deps: [{ token: FilterService }, { token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
769
- FilterExpressionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterExpressionComponent, selector: "kendo-filter-expression", inputs: { index: "index", currentItem: "currentItem" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
770
- <div class="k-filter-toolbar" role="group" [attr.aria-label]="messageFor('filterAriaLabel')">
771
- <div class="k-toolbar">
772
- <div class="k-filter-toolbar-item k-filter-field">
1055
+ FilterExpressionComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterExpressionComponent, deps: [{ token: FilterService }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: NavigationService }, { token: i1.LocalizationService }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
1056
+ FilterExpressionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterExpressionComponent, selector: "kendo-filter-expression", inputs: { currentItem: "currentItem" }, providers: [{
1057
+ provide: FilterItem,
1058
+ useExisting: forwardRef(() => FilterExpressionComponent)
1059
+ }], usesInheritance: true, ngImport: i0, template: `
1060
+ <div class="k-filter-toolbar">
1061
+ <div class="k-toolbar" role="toolbar" [attr.aria-label]="messageFor('filterToolbarAriaLabel')" (focus)="onFocus()" (focusout)="onBlur()" (mousedown)="onMouseDown($event)">
1062
+ <div class="k-filter-toolbar-item k-filter-field k-toolbar-item" >
773
1063
  <kendo-dropdownlist
1064
+ [tabindex]="-1"
774
1065
  [kendoAriaLabelValue]="messageFor('filterFieldAriaLabel')"
775
1066
  [title]="messageFor('filterExpressionFilters')"
776
1067
  [data]="filters"
@@ -781,7 +1072,7 @@ FilterExpressionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.
781
1072
  (valueChange)="filterValueChange($event)">
782
1073
  </kendo-dropdownlist>
783
1074
  </div>
784
- <div *ngIf="!isBoolean" class="k-filter-toolbar-item k-filter-operator">
1075
+ <div *ngIf="!isBoolean" class="k-filter-toolbar-item k-filter-operator k-toolbar-item" >
785
1076
  <kendo-filter-expression-operators
786
1077
  [currentItem]="currentItem"
787
1078
  [operators]="operators"
@@ -790,7 +1081,7 @@ FilterExpressionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.
790
1081
  </kendo-filter-expression-operators>
791
1082
  </div>
792
1083
 
793
- <div class="k-filter-toolbar-item k-filter-value">
1084
+ <div class="k-filter-toolbar-item k-filter-value k-toolbar-item">
794
1085
  <ng-container *ngIf="!editorTemplate" [ngSwitch]="getEditorType()">
795
1086
  <kendo-filter-text-editor *ngSwitchCase="'string'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-text-editor>
796
1087
  <kendo-filter-numeric-editor *ngSwitchCase="'number'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" [format]="numericEditorFormat" (valueChange)="valueChange.emit()"></kendo-filter-numeric-editor>
@@ -804,9 +1095,10 @@ FilterExpressionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.
804
1095
  </ng-container>
805
1096
  </div>
806
1097
 
807
- <div class="k-filter-toolbar-item">
1098
+ <div class="k-filter-toolbar-item k-toolbar-item" >
808
1099
  <button
809
1100
  kendoButton
1101
+ tabindex="-1"
810
1102
  icon="x"
811
1103
  fillMode="flat"
812
1104
  [title]="messageFor('remove')"
@@ -815,16 +1107,21 @@ FilterExpressionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.
815
1107
  </div>
816
1108
  </div>
817
1109
  </div>
818
- `, isInline: true, components: [{ type: i2.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["iconClass", "loading", "data", "value", "textField", "valueField", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { type: FilterExpressionOperatorsComponent, selector: "kendo-filter-expression-operators", inputs: ["currentItem", "editorType", "operators"], outputs: ["valueChange"] }, { type: FilterTextEditorComponent, selector: "kendo-filter-text-editor", inputs: ["currentItem", "isDisabled"], outputs: ["valueChange"] }, { type: FilterNumericEditorComponent, selector: "kendo-filter-numeric-editor", inputs: ["currentItem", "isDisabled", "format"], outputs: ["valueChange"] }, { type: FilterBooleanEditorComponent, selector: "kendo-filter-boolean-editor", inputs: ["currentItem"], outputs: ["valueChange"] }, { type: FilterDateEditorComponent, selector: "kendo-filter-date-editor", inputs: ["currentItem", "isDisabled", "format"], outputs: ["valueChange"] }], directives: [{ type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: ["kendoAriaLabelValue"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i10.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i10.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i11.TemplateContextDirective, selector: "[templateContext]", inputs: ["templateContext"] }, { type: i11.ButtonDirective, selector: "button[kendoButton], span[kendoButton]", inputs: ["toggleable", "togglable", "selected", "tabIndex", "icon", "iconClass", "imageUrl", "disabled", "size", "rounded", "fillMode", "themeColor", "role", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
1110
+ `, isInline: true, components: [{ type: i2.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["iconClass", "loading", "data", "value", "textField", "valueField", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { type: FilterExpressionOperatorsComponent, selector: "kendo-filter-expression-operators", inputs: ["currentItem", "editorType", "operators"], outputs: ["valueChange"] }, { type: FilterTextEditorComponent, selector: "kendo-filter-text-editor", inputs: ["currentItem", "isDisabled"], outputs: ["valueChange"] }, { type: FilterNumericEditorComponent, selector: "kendo-filter-numeric-editor", inputs: ["currentItem", "isDisabled", "format"], outputs: ["valueChange"] }, { type: FilterBooleanEditorComponent, selector: "kendo-filter-boolean-editor", inputs: ["currentItem"], outputs: ["valueChange"] }, { type: FilterDateEditorComponent, selector: "kendo-filter-date-editor", inputs: ["currentItem", "isDisabled", "format"], outputs: ["valueChange"] }], directives: [{ type: AriaLabelValueDirective, selector: "[kendoAriaLabelValue]", inputs: ["kendoAriaLabelValue"] }, { type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i11.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i11.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i12.TemplateContextDirective, selector: "[templateContext]", inputs: ["templateContext"] }, { type: i12.ButtonDirective, selector: "button[kendoButton], span[kendoButton]", inputs: ["toggleable", "togglable", "selected", "tabIndex", "icon", "iconClass", "imageUrl", "disabled", "size", "rounded", "fillMode", "themeColor", "role", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
819
1111
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterExpressionComponent, decorators: [{
820
1112
  type: Component,
821
1113
  args: [{
1114
+ providers: [{
1115
+ provide: FilterItem,
1116
+ useExisting: forwardRef(() => FilterExpressionComponent)
1117
+ }],
822
1118
  selector: 'kendo-filter-expression',
823
1119
  template: `
824
- <div class="k-filter-toolbar" role="group" [attr.aria-label]="messageFor('filterAriaLabel')">
825
- <div class="k-toolbar">
826
- <div class="k-filter-toolbar-item k-filter-field">
1120
+ <div class="k-filter-toolbar">
1121
+ <div class="k-toolbar" role="toolbar" [attr.aria-label]="messageFor('filterToolbarAriaLabel')" (focus)="onFocus()" (focusout)="onBlur()" (mousedown)="onMouseDown($event)">
1122
+ <div class="k-filter-toolbar-item k-filter-field k-toolbar-item" >
827
1123
  <kendo-dropdownlist
1124
+ [tabindex]="-1"
828
1125
  [kendoAriaLabelValue]="messageFor('filterFieldAriaLabel')"
829
1126
  [title]="messageFor('filterExpressionFilters')"
830
1127
  [data]="filters"
@@ -835,7 +1132,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
835
1132
  (valueChange)="filterValueChange($event)">
836
1133
  </kendo-dropdownlist>
837
1134
  </div>
838
- <div *ngIf="!isBoolean" class="k-filter-toolbar-item k-filter-operator">
1135
+ <div *ngIf="!isBoolean" class="k-filter-toolbar-item k-filter-operator k-toolbar-item" >
839
1136
  <kendo-filter-expression-operators
840
1137
  [currentItem]="currentItem"
841
1138
  [operators]="operators"
@@ -844,7 +1141,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
844
1141
  </kendo-filter-expression-operators>
845
1142
  </div>
846
1143
 
847
- <div class="k-filter-toolbar-item k-filter-value">
1144
+ <div class="k-filter-toolbar-item k-filter-value k-toolbar-item">
848
1145
  <ng-container *ngIf="!editorTemplate" [ngSwitch]="getEditorType()">
849
1146
  <kendo-filter-text-editor *ngSwitchCase="'string'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" (valueChange)="valueChange.emit()"></kendo-filter-text-editor>
850
1147
  <kendo-filter-numeric-editor *ngSwitchCase="'number'" [currentItem]="currentItem" [isDisabled]="isEditorDisabled" [format]="numericEditorFormat" (valueChange)="valueChange.emit()"></kendo-filter-numeric-editor>
@@ -858,9 +1155,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
858
1155
  </ng-container>
859
1156
  </div>
860
1157
 
861
- <div class="k-filter-toolbar-item">
1158
+ <div class="k-filter-toolbar-item k-toolbar-item" >
862
1159
  <button
863
1160
  kendoButton
1161
+ tabindex="-1"
864
1162
  icon="x"
865
1163
  fillMode="flat"
866
1164
  [title]="messageFor('remove')"
@@ -871,30 +1169,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
871
1169
  </div>
872
1170
  `
873
1171
  }]
874
- }], ctorParameters: function () { return [{ type: FilterService }, { type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { index: [{
1172
+ }], ctorParameters: function () { return [{ type: FilterService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: NavigationService }, { type: i1.LocalizationService }, { type: i0.Renderer2 }]; }, propDecorators: { currentItem: [{
875
1173
  type: Input
876
- }], currentItem: [{
877
- type: Input
878
- }], valueChange: [{
879
- type: Output
880
1174
  }] } });
881
1175
 
882
1176
  /**
883
1177
  * @hidden
884
1178
  */
885
- class FilterGroupComponent {
886
- constructor(filterService, localization, cdr) {
1179
+ class FilterGroupComponent extends BaseFilterRowComponent {
1180
+ constructor(filterService, cdr, element, navigationService, localization, renderer) {
1181
+ super(element, navigationService, localization, renderer);
887
1182
  this.filterService = filterService;
888
- this.localization = localization;
889
1183
  this.cdr = cdr;
890
- this.index = 0;
891
1184
  this.currentItem = {
892
1185
  logic: 'or',
893
1186
  filters: []
894
1187
  };
895
- this.valueChange = new EventEmitter();
896
1188
  this.operators = [];
897
1189
  }
1190
+ get filterItems() {
1191
+ return this._filterItems.toArray();
1192
+ }
898
1193
  ngOnInit() {
899
1194
  this.operators = this.getLogicOperators();
900
1195
  this.localizationSubscription = this.localization.changes.subscribe(() => {
@@ -910,9 +1205,6 @@ class FilterGroupComponent {
910
1205
  getLogicOperators() {
911
1206
  return localizeOperators(logicOperators)(this.localization);
912
1207
  }
913
- messageFor(key) {
914
- return this.localization.get(key);
915
- }
916
1208
  getOperator(operatorValue) {
917
1209
  return this.messageFor(getKeyByValue(logicOperators, operatorValue));
918
1210
  }
@@ -932,16 +1224,44 @@ class FilterGroupComponent {
932
1224
  }
933
1225
  removeFilterGroup() {
934
1226
  this.filterService.remove(this.currentItem, this.index);
935
- this.valueChange.emit();
1227
+ this.cdr.detectChanges();
1228
+ this.valueChange.emit(true);
1229
+ }
1230
+ onMouseDown(event) {
1231
+ let elementToFocus;
1232
+ if (event.target.closest(selectors.kendoFilterToolbarItem)) {
1233
+ let index = Array.from(event.target.closest(selectors.kendoToolbar).children).indexOf(event.target.closest(selectors.kendoFilterToolbarItem)) + 1;
1234
+ if (event.target.closest(selectors.andButton)) {
1235
+ index = 0;
1236
+ }
1237
+ if (event.target.closest(selectors.orButton)) {
1238
+ index = 1;
1239
+ }
1240
+ this.navigationService.currentToolbarItemChildrenIndex = index;
1241
+ this.navigationService.isInnerNavigationActivated = true;
1242
+ elementToFocus = this.navigationService.flattenFilterItems[this.itemNumber].focusableChildren[index];
1243
+ }
1244
+ else {
1245
+ this.navigationService.currentToolbarItemChildrenIndex = 0;
1246
+ this.navigationService.isInnerNavigationActivated = false;
1247
+ elementToFocus = this.navigationService.flattenFilterItems[this.itemNumber].toolbarElement;
1248
+ }
1249
+ this.navigationService.isFilterExpressionComponentFocused = false;
1250
+ this.navigationService.currentToolbarItemIndex = this.itemNumber;
1251
+ this.navigationService.focusCurrentElement(elementToFocus, true);
936
1252
  }
937
1253
  }
938
- FilterGroupComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterGroupComponent, deps: [{ token: FilterService }, { token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
939
- FilterGroupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterGroupComponent, selector: "kendo-filter-group", inputs: { index: "index", currentItem: "currentItem" }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
940
- <div class="k-filter-toolbar" role="toolbar" [attr.aria-label]="messageFor('filterToolbarAriaLabel')">
941
- <div class="k-toolbar">
1254
+ FilterGroupComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterGroupComponent, deps: [{ token: FilterService }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: NavigationService }, { token: i1.LocalizationService }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
1255
+ FilterGroupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterGroupComponent, selector: "kendo-filter-group", inputs: { currentItem: "currentItem" }, providers: [{
1256
+ provide: FilterItem,
1257
+ useExisting: forwardRef(() => FilterGroupComponent)
1258
+ }], viewQueries: [{ propertyName: "_filterItems", predicate: FilterItem, descendants: true }], usesInheritance: true, ngImport: i0, template: `
1259
+ <div class="k-filter-toolbar">
1260
+ <div class="k-toolbar" role="toolbar" [attr.aria-label]="messageFor('filterToolbarAriaLabel')" (focus)="onFocus()" (focusout)="onBlur()" (mousedown)="onMouseDown($event)">
942
1261
  <div class="k-filter-toolbar-item">
943
1262
  <div class="k-widget k-button-group" role="group">
944
- <button
1263
+ <button
1264
+ tabindex="-1"
945
1265
  *ngFor="let operator of operators"
946
1266
  kendoButton
947
1267
  [ngClass]="{'k-group-start': operator.value === 'and', 'k-group-end': operator.value === 'or'}"
@@ -956,6 +1276,7 @@ FilterGroupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", v
956
1276
  <div class="k-filter-toolbar-item">
957
1277
  <button
958
1278
  kendoButton
1279
+ tabindex="-1"
959
1280
  [title]="messageFor('addFilter')"
960
1281
  icon="filter-add-expression"
961
1282
  (click)="addFilterExpression()">
@@ -965,6 +1286,7 @@ FilterGroupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", v
965
1286
  <div class="k-filter-toolbar-item">
966
1287
  <button
967
1288
  kendoButton
1289
+ tabindex="-1"
968
1290
  [title]="messageFor('addGroup')"
969
1291
  icon="filter-add-group"
970
1292
  (click)="addFilterGroup()">
@@ -974,6 +1296,7 @@ FilterGroupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", v
974
1296
  <div class="k-filter-toolbar-item">
975
1297
  <button
976
1298
  kendoButton
1299
+ tabindex="-1"
977
1300
  icon="x"
978
1301
  fillMode="flat"
979
1302
  [title]="messageFor('remove')"
@@ -983,15 +1306,15 @@ FilterGroupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", v
983
1306
  </div>
984
1307
  </div>
985
1308
 
986
- <ul class="k-filter-lines" *ngIf="currentItem.filters">
1309
+ <ul class="k-filter-lines" role="group" *ngIf="currentItem.filters">
987
1310
  <ng-container *ngFor="let item of currentItem.filters; let i = index;">
988
- <li class="k-filter-item" *ngIf="!item['filters']">
989
- <kendo-filter-expression (valueChange)="valueChange.emit()" [currentItem]="item" [index]="i">
1311
+ <li class="k-filter-item" role="treeitem" *ngIf="!item['filters']">
1312
+ <kendo-filter-expression (valueChange)="valueChange.emit($event)" [currentItem]="item" [index]="i">
990
1313
  </kendo-filter-expression>
991
1314
  </li>
992
- <li class="k-filter-item" *ngIf="item['filters']">
1315
+ <li class="k-filter-item" role="treeitem" *ngIf="item['filters']">
993
1316
  <kendo-filter-group
994
- (valueChange)="valueChange.emit()"
1317
+ (valueChange)="valueChange.emit($event)"
995
1318
  [currentItem]="item"
996
1319
  [index]="i"
997
1320
  >
@@ -999,17 +1322,22 @@ FilterGroupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", v
999
1322
  </li>
1000
1323
  </ng-container>
1001
1324
  </ul>
1002
- `, isInline: true, components: [{ type: FilterExpressionComponent, selector: "kendo-filter-expression", inputs: ["index", "currentItem"], outputs: ["valueChange"] }, { type: FilterGroupComponent, selector: "kendo-filter-group", inputs: ["index", "currentItem"], outputs: ["valueChange"] }], directives: [{ type: i10.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i11.ButtonDirective, selector: "button[kendoButton], span[kendoButton]", inputs: ["toggleable", "togglable", "selected", "tabIndex", "icon", "iconClass", "imageUrl", "disabled", "size", "rounded", "fillMode", "themeColor", "role", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { type: i10.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
1325
+ `, isInline: true, components: [{ type: FilterExpressionComponent, selector: "kendo-filter-expression", inputs: ["currentItem"] }, { type: FilterGroupComponent, selector: "kendo-filter-group", inputs: ["currentItem"] }], directives: [{ type: i11.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i12.ButtonDirective, selector: "button[kendoButton], span[kendoButton]", inputs: ["toggleable", "togglable", "selected", "tabIndex", "icon", "iconClass", "imageUrl", "disabled", "size", "rounded", "fillMode", "themeColor", "role", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { type: i11.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i11.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
1003
1326
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterGroupComponent, decorators: [{
1004
1327
  type: Component,
1005
1328
  args: [{
1329
+ providers: [{
1330
+ provide: FilterItem,
1331
+ useExisting: forwardRef(() => FilterGroupComponent)
1332
+ }],
1006
1333
  selector: 'kendo-filter-group',
1007
1334
  template: `
1008
- <div class="k-filter-toolbar" role="toolbar" [attr.aria-label]="messageFor('filterToolbarAriaLabel')">
1009
- <div class="k-toolbar">
1335
+ <div class="k-filter-toolbar">
1336
+ <div class="k-toolbar" role="toolbar" [attr.aria-label]="messageFor('filterToolbarAriaLabel')" (focus)="onFocus()" (focusout)="onBlur()" (mousedown)="onMouseDown($event)">
1010
1337
  <div class="k-filter-toolbar-item">
1011
1338
  <div class="k-widget k-button-group" role="group">
1012
- <button
1339
+ <button
1340
+ tabindex="-1"
1013
1341
  *ngFor="let operator of operators"
1014
1342
  kendoButton
1015
1343
  [ngClass]="{'k-group-start': operator.value === 'and', 'k-group-end': operator.value === 'or'}"
@@ -1024,6 +1352,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1024
1352
  <div class="k-filter-toolbar-item">
1025
1353
  <button
1026
1354
  kendoButton
1355
+ tabindex="-1"
1027
1356
  [title]="messageFor('addFilter')"
1028
1357
  icon="filter-add-expression"
1029
1358
  (click)="addFilterExpression()">
@@ -1033,6 +1362,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1033
1362
  <div class="k-filter-toolbar-item">
1034
1363
  <button
1035
1364
  kendoButton
1365
+ tabindex="-1"
1036
1366
  [title]="messageFor('addGroup')"
1037
1367
  icon="filter-add-group"
1038
1368
  (click)="addFilterGroup()">
@@ -1042,6 +1372,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1042
1372
  <div class="k-filter-toolbar-item">
1043
1373
  <button
1044
1374
  kendoButton
1375
+ tabindex="-1"
1045
1376
  icon="x"
1046
1377
  fillMode="flat"
1047
1378
  [title]="messageFor('remove')"
@@ -1051,15 +1382,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1051
1382
  </div>
1052
1383
  </div>
1053
1384
 
1054
- <ul class="k-filter-lines" *ngIf="currentItem.filters">
1385
+ <ul class="k-filter-lines" role="group" *ngIf="currentItem.filters">
1055
1386
  <ng-container *ngFor="let item of currentItem.filters; let i = index;">
1056
- <li class="k-filter-item" *ngIf="!item['filters']">
1057
- <kendo-filter-expression (valueChange)="valueChange.emit()" [currentItem]="item" [index]="i">
1387
+ <li class="k-filter-item" role="treeitem" *ngIf="!item['filters']">
1388
+ <kendo-filter-expression (valueChange)="valueChange.emit($event)" [currentItem]="item" [index]="i">
1058
1389
  </kendo-filter-expression>
1059
1390
  </li>
1060
- <li class="k-filter-item" *ngIf="item['filters']">
1391
+ <li class="k-filter-item" role="treeitem" *ngIf="item['filters']">
1061
1392
  <kendo-filter-group
1062
- (valueChange)="valueChange.emit()"
1393
+ (valueChange)="valueChange.emit($event)"
1063
1394
  [currentItem]="item"
1064
1395
  [index]="i"
1065
1396
  >
@@ -1069,12 +1400,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1069
1400
  </ul>
1070
1401
  `
1071
1402
  }]
1072
- }], ctorParameters: function () { return [{ type: FilterService }, { type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { index: [{
1073
- type: Input
1403
+ }], ctorParameters: function () { return [{ type: FilterService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: NavigationService }, { type: i1.LocalizationService }, { type: i0.Renderer2 }]; }, propDecorators: { _filterItems: [{
1404
+ type: ViewChildren,
1405
+ args: [FilterItem]
1074
1406
  }], currentItem: [{
1075
1407
  type: Input
1076
- }], valueChange: [{
1077
- type: Output
1078
1408
  }] } });
1079
1409
 
1080
1410
  /**
@@ -1083,7 +1413,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1083
1413
  class Messages extends ComponentMessages {
1084
1414
  }
1085
1415
  Messages.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: Messages, deps: null, target: i0.ɵɵFactoryTarget.Directive });
1086
- Messages.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.16", type: Messages, selector: "[kendoFilterMessages]", inputs: { filterExpressionOperators: "filterExpressionOperators", filterExpressionFilters: "filterExpressionFilters", remove: "remove", addGroup: "addGroup", addFilter: "addFilter", filterAndLogic: "filterAndLogic", filterOrLogic: "filterOrLogic", filterEqOperator: "filterEqOperator", filterNotEqOperator: "filterNotEqOperator", filterIsNullOperator: "filterIsNullOperator", filterIsNotNullOperator: "filterIsNotNullOperator", filterIsEmptyOperator: "filterIsEmptyOperator", filterIsNotEmptyOperator: "filterIsNotEmptyOperator", filterStartsWithOperator: "filterStartsWithOperator", filterContainsOperator: "filterContainsOperator", filterNotContainsOperator: "filterNotContainsOperator", filterEndsWithOperator: "filterEndsWithOperator", filterGteOperator: "filterGteOperator", filterGtOperator: "filterGtOperator", filterLteOperator: "filterLteOperator", filterLtOperator: "filterLtOperator", filterIsTrue: "filterIsTrue", filterIsFalse: "filterIsFalse", filterBooleanAll: "filterBooleanAll", filterAfterOrEqualOperator: "filterAfterOrEqualOperator", filterAfterOperator: "filterAfterOperator", filterBeforeOperator: "filterBeforeOperator", filterBeforeOrEqualOperator: "filterBeforeOrEqualOperator", editorNumericDecrement: "editorNumericDecrement", editorNumericIncrement: "editorNumericIncrement", editorDateTodayText: "editorDateTodayText", editorDateToggleText: "editorDateToggleText", filterFieldAriaLabel: "filterFieldAriaLabel", filterOperatorAriaLabel: "filterOperatorAriaLabel", filterValueAriaLabel: "filterValueAriaLabel", filterAriaLabel: "filterAriaLabel", filterToolbarAriaLabel: "filterToolbarAriaLabel" }, usesInheritance: true, ngImport: i0 });
1416
+ Messages.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "12.2.16", type: Messages, selector: "[kendoFilterMessages]", inputs: { filterExpressionOperators: "filterExpressionOperators", filterExpressionFilters: "filterExpressionFilters", remove: "remove", addGroup: "addGroup", addFilter: "addFilter", filterAndLogic: "filterAndLogic", filterOrLogic: "filterOrLogic", filterEqOperator: "filterEqOperator", filterNotEqOperator: "filterNotEqOperator", filterIsNullOperator: "filterIsNullOperator", filterIsNotNullOperator: "filterIsNotNullOperator", filterIsEmptyOperator: "filterIsEmptyOperator", filterIsNotEmptyOperator: "filterIsNotEmptyOperator", filterStartsWithOperator: "filterStartsWithOperator", filterContainsOperator: "filterContainsOperator", filterNotContainsOperator: "filterNotContainsOperator", filterEndsWithOperator: "filterEndsWithOperator", filterGteOperator: "filterGteOperator", filterGtOperator: "filterGtOperator", filterLteOperator: "filterLteOperator", filterLtOperator: "filterLtOperator", filterIsTrue: "filterIsTrue", filterIsFalse: "filterIsFalse", filterBooleanAll: "filterBooleanAll", filterAfterOrEqualOperator: "filterAfterOrEqualOperator", filterAfterOperator: "filterAfterOperator", filterBeforeOperator: "filterBeforeOperator", filterBeforeOrEqualOperator: "filterBeforeOrEqualOperator", editorNumericDecrement: "editorNumericDecrement", editorNumericIncrement: "editorNumericIncrement", editorDateTodayText: "editorDateTodayText", editorDateToggleText: "editorDateToggleText", filterFieldAriaLabel: "filterFieldAriaLabel", filterOperatorAriaLabel: "filterOperatorAriaLabel", filterValueAriaLabel: "filterValueAriaLabel", filterToolbarAriaLabel: "filterToolbarAriaLabel", filterComponentAriaLabel: "filterComponentAriaLabel" }, usesInheritance: true, ngImport: i0 });
1087
1417
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: Messages, decorators: [{
1088
1418
  type: Directive,
1089
1419
  args: [{
@@ -1159,10 +1489,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1159
1489
  type: Input
1160
1490
  }], filterValueAriaLabel: [{
1161
1491
  type: Input
1162
- }], filterAriaLabel: [{
1163
- type: Input
1164
1492
  }], filterToolbarAriaLabel: [{
1165
1493
  type: Input
1494
+ }], filterComponentAriaLabel: [{
1495
+ type: Input
1166
1496
  }] } });
1167
1497
 
1168
1498
  /**
@@ -1227,10 +1557,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1227
1557
  * ```
1228
1558
  */
1229
1559
  class FilterComponent {
1230
- constructor(filterService, localization, cdr) {
1560
+ constructor(filterService, localization, cdr, element, navigationService, renderer) {
1231
1561
  this.filterService = filterService;
1232
1562
  this.localization = localization;
1233
1563
  this.cdr = cdr;
1564
+ this.element = element;
1565
+ this.navigationService = navigationService;
1566
+ this.renderer = renderer;
1234
1567
  /**
1235
1568
  * Fires every time the Filter component value is updated.
1236
1569
  * That is each time a Filter Group or Filter Expression is added, removed, or updated.
@@ -1240,6 +1573,31 @@ class FilterComponent {
1240
1573
  validatePackage(packageMetadata);
1241
1574
  this.direction = localization.rtl ? 'rtl' : 'ltr';
1242
1575
  }
1576
+ /**
1577
+ * @hidden
1578
+ */
1579
+ focusout() {
1580
+ setTimeout(() => {
1581
+ if (!(document.activeElement.closest('.k-filter'))) {
1582
+ this.renderer.setAttribute(this.navigationService.currentlyFocusedElement, 'tabindex', '-1');
1583
+ this.navigationService.currentlyFocusedElement = this.navigationService.flattenFilterItems[this.navigationService.currentToolbarItemIndex].toolbarElement;
1584
+ this.renderer.setAttribute(this.navigationService.currentlyFocusedElement, 'tabindex', '0');
1585
+ this.navigationService.isInnerNavigationActivated = false;
1586
+ this.navigationService.isFilterExpressionComponentFocused = false;
1587
+ }
1588
+ });
1589
+ }
1590
+ /**
1591
+ * @hidden
1592
+ */
1593
+ onKeydown(event) {
1594
+ const keyCode = event.keyCode;
1595
+ const keys = [Keys.ArrowUp, Keys.ArrowDown, Keys.ArrowLeft, Keys.ArrowRight, Keys.Enter,
1596
+ Keys.Escape, Keys.Tab];
1597
+ if (keys.indexOf(keyCode) > -1) {
1598
+ this.navigationService.processKeyDown(keyCode, event);
1599
+ }
1600
+ }
1243
1601
  /**
1244
1602
  * Specifies the available user-defined filters. At least one filter should be provided.
1245
1603
  */
@@ -1271,13 +1629,19 @@ class FilterComponent {
1271
1629
  get value() {
1272
1630
  return this._value;
1273
1631
  }
1632
+ get filterItems() {
1633
+ return this._filterItems.toArray();
1634
+ }
1635
+ get toolbarElement() {
1636
+ return this.element.nativeElement.querySelector('.k-toolbar');
1637
+ }
1274
1638
  ngOnInit() {
1275
1639
  this.localizationSubscription = this.localization.changes.subscribe(({ rtl }) => {
1276
1640
  this.direction = rtl ? 'rtl' : 'ltr';
1277
1641
  this.cdr.detectChanges();
1278
1642
  });
1279
1643
  }
1280
- ngAfterViewChecked() {
1644
+ ngAfterViewInit() {
1281
1645
  if (this.filterFields && this.filterFields.length > 0) {
1282
1646
  this.filters = this.filterFields.map((filterField) => {
1283
1647
  var _a;
@@ -1285,7 +1649,13 @@ class FilterComponent {
1285
1649
  });
1286
1650
  }
1287
1651
  if (this.filters.length === 0) {
1288
- throw new Error(`Pass at least one user-defined filter through the [filters] input property or nest kendo-filter-field components. See http://www.telerik.com/kendo-angular-ui/components/filter/#data-binding`);
1652
+ throw new Error(FilterErrorMessages.missingFilters);
1653
+ }
1654
+ this.navigationService.reset(this.filterItems);
1655
+ if (!this.navigationService.currentlyFocusedElement) {
1656
+ const firstElement = this.navigationService.flattenFilterItems[0].toolbarElement;
1657
+ this.navigationService.currentlyFocusedElement = firstElement;
1658
+ this.renderer.setAttribute(firstElement, 'tabindex', '0');
1289
1659
  }
1290
1660
  }
1291
1661
  ngOnDestroy() {
@@ -1302,22 +1672,35 @@ class FilterComponent {
1302
1672
  /**
1303
1673
  * @hidden
1304
1674
  */
1305
- onValueChange() {
1675
+ onValueChange(isRemoveOperation) {
1306
1676
  this.valueChange.emit(this.filterService.normalizedValue);
1677
+ this.cdr.detectChanges();
1678
+ this.navigationService.reset(this.filterItems);
1679
+ if (isRemoveOperation) {
1680
+ if (this.navigationService.currentToolbarItemIndex === this.navigationService.flattenFilterItems.length) {
1681
+ this.navigationService.currentToolbarItemIndex -= 1;
1682
+ }
1683
+ this.navigationService.isInnerNavigationActivated = false;
1684
+ this.navigationService.isFilterExpressionComponentFocused = false;
1685
+ this.navigationService.currentlyFocusedElement = this.navigationService.flattenFilterItems[this.navigationService.currentToolbarItemIndex].toolbarElement;
1686
+ this.renderer.setAttribute(this.navigationService.currentlyFocusedElement, 'tabindex', '0');
1687
+ this.renderer.addClass(this.navigationService.currentlyFocusedElement, 'k-focus');
1688
+ this.navigationService.currentlyFocusedElement.focus();
1689
+ }
1307
1690
  }
1308
1691
  normalizeFilter(filterDescriptor) {
1309
1692
  const foundFilter = this.filterService.filters.find((filter) => filter.field === filterDescriptor.field);
1310
1693
  if (isDevMode() && !foundFilter) {
1311
- throw new Error(`There is no user-defined filter with '${filterDescriptor.field}' field provided through the [filters] input property.`);
1694
+ throw new Error(FilterErrorMessages.missingFilterForUsedField(filterDescriptor.field));
1312
1695
  }
1313
1696
  if (isDevMode() && foundFilter.editor === 'boolean' && (!filterDescriptor.value && filterDescriptor.value !== false)) {
1314
- console.warn(`Provide a value for the boolean '${filterDescriptor.field}' user-defined filter as the operator is always set to 'eq'.`);
1697
+ console.warn(FilterErrorMessages.missingValueForBooleanField(filterDescriptor.field));
1315
1698
  }
1316
1699
  if (isDevMode() && foundFilter.editor === 'boolean' && filterDescriptor.operator !== 'eq') {
1317
- console.warn(`The operator of the boolean '${filterDescriptor.field}' user-defined filter is always set to 'eq'.`);
1700
+ console.warn(FilterErrorMessages.operatorBooleanField(filterDescriptor.field));
1318
1701
  }
1319
1702
  if (filterDescriptor.operator && foundFilter.operators && !foundFilter.operators.some(operator => operator === filterDescriptor.operator)) {
1320
- throw new Error(`The user-defined filter with field '${filterDescriptor.field}' is missing the '${filterDescriptor.operator}' operator.`);
1703
+ throw new Error(FilterErrorMessages.filterMissingUsedOperator(filterDescriptor.field, filterDescriptor.operator));
1321
1704
  }
1322
1705
  if (foundFilter.editor === 'boolean') {
1323
1706
  filterDescriptor.operator = 'eq';
@@ -1350,16 +1733,23 @@ class FilterComponent {
1350
1733
  }
1351
1734
  });
1352
1735
  }
1736
+ /**
1737
+ * @hidden
1738
+ */
1739
+ messageFor(key) {
1740
+ return this.localization.get(key);
1741
+ }
1353
1742
  }
1354
- FilterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterComponent, deps: [{ token: FilterService }, { token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1355
- FilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterComponent, selector: "kendo-filter", inputs: { filters: "filters", value: "value" }, outputs: { valueChange: "valueChange" }, host: { properties: { "attr.dir": "this.direction" } }, providers: [
1743
+ FilterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterComponent, deps: [{ token: FilterService }, { token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: NavigationService }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
1744
+ FilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FilterComponent, selector: "kendo-filter", inputs: { filters: "filters", value: "value" }, outputs: { valueChange: "valueChange" }, host: { listeners: { "focusout": "focusout($event)", "keydown": "onKeydown($event)" }, properties: { "attr.dir": "this.direction" } }, providers: [
1356
1745
  LocalizationService,
1357
1746
  {
1358
1747
  provide: L10N_PREFIX,
1359
1748
  useValue: 'kendo.filter'
1360
1749
  },
1361
- FilterService
1362
- ], queries: [{ propertyName: "filterFields", predicate: FilterFieldComponent }], ngImport: i0, template: `
1750
+ FilterService,
1751
+ NavigationService
1752
+ ], queries: [{ propertyName: "filterFields", predicate: FilterFieldComponent }], viewQueries: [{ propertyName: "_filterItems", predicate: FilterItem, descendants: true }], ngImport: i0, template: `
1363
1753
  <ng-container kendoFilterLocalizedMessages
1364
1754
  i18n-editorDateTodayText="kendo.filter.editorDateTodayText|The text of the Today button of the Date editor"
1365
1755
  editorDateTodayText="Today"
@@ -1466,25 +1856,25 @@ FilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", versio
1466
1856
  i18n-filterValueAriaLabel="kendo.filter.filterValueAriaLabel|The text of the filter value aria label"
1467
1857
  filterValueAriaLabel="value"
1468
1858
 
1469
- i18n-filterAriaLabel="kendo.filter.filterAriaLabel|The text of the filter row aria label"
1470
- filterAriaLabel="filter"
1859
+ i18n-filterToolbarAriaLabel="kendo.filter.filterToolbarAriaLabel|The text of the filter row aria label"
1860
+ filterToolbarAriaLabel="filter row settings"
1471
1861
 
1472
- i18n-filterToolbarAriaLabel="kendo.filter.filterToolbarAriaLabel|The text of the filter toolbar aria label"
1473
- filterToolbarAriaLabel="filter settings"
1862
+ i18n-filterComponentAriaLabel="kendo.filter.filterComponentAriaLabel|The text of the filter component aria label"
1863
+ filterComponentAriaLabel="filter component"
1474
1864
  >
1475
1865
  </ng-container>
1476
1866
  <div class="k-widget k-filter" [attr.dir]="direction">
1477
- <ul class='k-filter-container'>
1478
- <li class='k-filter-group-main'>
1867
+ <ul class='k-filter-container' role="tree" [attr.aria-label]="messageFor('filterComponentAriaLabel')">
1868
+ <li class='k-filter-group-main' role="treeitem">
1479
1869
  <kendo-filter-group
1480
1870
  [currentItem]="getCurrentFilter()"
1481
- (valueChange)="onValueChange()"
1871
+ (valueChange)="onValueChange($event)"
1482
1872
  >
1483
1873
  </kendo-filter-group>
1484
1874
  </li>
1485
1875
  </ul>
1486
1876
  </div>
1487
- `, isInline: true, components: [{ type: FilterGroupComponent, selector: "kendo-filter-group", inputs: ["index", "currentItem"], outputs: ["valueChange"] }], directives: [{ type: LocalizedMessagesDirective, selector: "[kendoFilterLocalizedMessages]" }] });
1877
+ `, isInline: true, components: [{ type: FilterGroupComponent, selector: "kendo-filter-group", inputs: ["currentItem"] }], directives: [{ type: LocalizedMessagesDirective, selector: "[kendoFilterLocalizedMessages]" }] });
1488
1878
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FilterComponent, decorators: [{
1489
1879
  type: Component,
1490
1880
  args: [{
@@ -1494,7 +1884,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1494
1884
  provide: L10N_PREFIX,
1495
1885
  useValue: 'kendo.filter'
1496
1886
  },
1497
- FilterService
1887
+ FilterService,
1888
+ NavigationService
1498
1889
  ],
1499
1890
  selector: 'kendo-filter',
1500
1891
  template: `
@@ -1604,19 +1995,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1604
1995
  i18n-filterValueAriaLabel="kendo.filter.filterValueAriaLabel|The text of the filter value aria label"
1605
1996
  filterValueAriaLabel="value"
1606
1997
 
1607
- i18n-filterAriaLabel="kendo.filter.filterAriaLabel|The text of the filter row aria label"
1608
- filterAriaLabel="filter"
1998
+ i18n-filterToolbarAriaLabel="kendo.filter.filterToolbarAriaLabel|The text of the filter row aria label"
1999
+ filterToolbarAriaLabel="filter row settings"
1609
2000
 
1610
- i18n-filterToolbarAriaLabel="kendo.filter.filterToolbarAriaLabel|The text of the filter toolbar aria label"
1611
- filterToolbarAriaLabel="filter settings"
2001
+ i18n-filterComponentAriaLabel="kendo.filter.filterComponentAriaLabel|The text of the filter component aria label"
2002
+ filterComponentAriaLabel="filter component"
1612
2003
  >
1613
2004
  </ng-container>
1614
2005
  <div class="k-widget k-filter" [attr.dir]="direction">
1615
- <ul class='k-filter-container'>
1616
- <li class='k-filter-group-main'>
2006
+ <ul class='k-filter-container' role="tree" [attr.aria-label]="messageFor('filterComponentAriaLabel')">
2007
+ <li class='k-filter-group-main' role="treeitem">
1617
2008
  <kendo-filter-group
1618
2009
  [currentItem]="getCurrentFilter()"
1619
- (valueChange)="onValueChange()"
2010
+ (valueChange)="onValueChange($event)"
1620
2011
  >
1621
2012
  </kendo-filter-group>
1622
2013
  </li>
@@ -1624,7 +2015,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1624
2015
  </div>
1625
2016
  `
1626
2017
  }]
1627
- }], ctorParameters: function () { return [{ type: FilterService }, { type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { direction: [{
2018
+ }], ctorParameters: function () { return [{ type: FilterService }, { type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: NavigationService }, { type: i0.Renderer2 }]; }, propDecorators: { focusout: [{
2019
+ type: HostListener,
2020
+ args: ['focusout', ['$event']]
2021
+ }], onKeydown: [{
2022
+ type: HostListener,
2023
+ args: ['keydown', ['$event']]
2024
+ }], direction: [{
1628
2025
  type: HostBinding,
1629
2026
  args: ['attr.dir']
1630
2027
  }], filters: [{
@@ -1636,6 +2033,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1636
2033
  }], filterFields: [{
1637
2034
  type: ContentChildren,
1638
2035
  args: [FilterFieldComponent]
2036
+ }], _filterItems: [{
2037
+ type: ViewChildren,
2038
+ args: [FilterItem]
1639
2039
  }] } });
1640
2040
 
1641
2041
  /**
@@ -1801,7 +2201,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1801
2201
  CustomMessagesComponent,
1802
2202
  AriaLabelValueDirective,
1803
2203
  FilterFieldComponent,
1804
- FilterValueEditorTemplateDirective]
2204
+ FilterValueEditorTemplateDirective
2205
+ ]
1805
2206
  }]
1806
2207
  }] });
1807
2208