@clr/angular 12.2.0 → 12.4.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.
@@ -4,7 +4,7 @@ import * as i1 from '@angular/common';
4
4
  import { CommonModule, isPlatformBrowser, DOCUMENT, NgForOf, getLocaleDayNames, FormStyle, TranslationWidth, getLocaleMonthNames, getLocaleFirstDayOfWeek, getLocaleDateFormat, FormatWidth } from '@angular/common';
5
5
  import { ClarityIcons, angleIcon, exclamationCircleIcon, checkCircleIcon, ellipsisHorizontalIcon, windowCloseIcon, eventIcon, calendarIcon, eyeHideIcon, eyeIcon, ellipsisVerticalIcon, viewColumnsIcon, arrowIcon, timesIcon, stepForward2Icon, angleDoubleIcon, filterGridCircleIcon, filterGridIcon, infoCircleIcon, exclamationTriangleIcon, circleIcon, dotCircleIcon, errorStandardIcon, successStandardIcon } from '@cds/core/icon';
6
6
  import { map, tap, startWith, distinctUntilChanged, pairwise, filter, debounceTime, take, first, switchMap, takeUntil } from 'rxjs/operators';
7
- import { Subject, BehaviorSubject, fromEvent, isObservable, of, ReplaySubject, combineLatest, Observable } from 'rxjs';
7
+ import { Subject, BehaviorSubject, Observable, fromEvent, isObservable, of, ReplaySubject, combineLatest } from 'rxjs';
8
8
  import { trigger, transition, style, animate, keyframes, state } from '@angular/animations';
9
9
  import { FormControl, FormGroup, FormGroupName, NgModelGroup, FormGroupDirective, NgForm, NgControl, FormsModule, SelectMultipleControlValueAccessor } from '@angular/forms';
10
10
  import { FocusTrapTrackerService, createId, isFocusable, isHTMLElement } from '@cds/core/internal';
@@ -1136,9 +1136,7 @@ class ClrStepper {
1136
1136
  this.subscriptions.forEach(s => s.unsubscribe());
1137
1137
  }
1138
1138
  listenForFormResetChanges() {
1139
- return this.form.statusChanges
1140
- .pipe(filter(() => this.form.pristine)) // https://github.com/angular/angular/issues/10887
1141
- .subscribe(() => this.stepperService.resetPanels());
1139
+ return fromControlReset(this.form.form).subscribe(() => this.stepperService.resetPanels());
1142
1140
  }
1143
1141
  listenForPanelsCompleted() {
1144
1142
  return this.stepperService.panelsCompleted.subscribe(panelsCompleted => {
@@ -1184,6 +1182,18 @@ ClrStepper.propDecorators = {
1184
1182
  initialPanel: [{ type: Input, args: ['clrInitialStep',] }],
1185
1183
  panels: [{ type: ContentChildren, args: [ClrStepperPanel, { descendants: true },] }]
1186
1184
  };
1185
+ function fromControlReset(control) {
1186
+ return new Observable(observer => {
1187
+ const unpatchedControlReset = control.reset;
1188
+ control.reset = () => {
1189
+ observer.next();
1190
+ unpatchedControlReset.apply(control);
1191
+ };
1192
+ return () => {
1193
+ control.reset = unpatchedControlReset;
1194
+ };
1195
+ });
1196
+ }
1187
1197
 
1188
1198
  /*
1189
1199
  * Copyright (c) 2016-2022 VMware, Inc. All Rights Reserved.
@@ -12999,6 +13009,10 @@ class Selection {
12999
13009
  * Subscriptions to the other providers changes.
13000
13010
  */
13001
13011
  this.subscriptions = [];
13012
+ /**
13013
+ * Shift key state, for use in range selection.
13014
+ */
13015
+ this.shiftPressed = false;
13002
13016
  this.valueCollector = new Subject();
13003
13017
  /**
13004
13018
  * The Observable that lets other classes subscribe to selection changes
@@ -13386,7 +13400,7 @@ WrappedRow.propDecorators = {
13386
13400
  */
13387
13401
  let nbRow = 0;
13388
13402
  class ClrDatagridRow {
13389
- constructor(selection, rowActionService, globalExpandable, expand, detailService, displayMode, vcr, renderer, el, commonStrings) {
13403
+ constructor(selection, rowActionService, globalExpandable, expand, detailService, displayMode, vcr, renderer, el, commonStrings, items, document) {
13390
13404
  this.selection = selection;
13391
13405
  this.rowActionService = rowActionService;
13392
13406
  this.globalExpandable = globalExpandable;
@@ -13397,6 +13411,8 @@ class ClrDatagridRow {
13397
13411
  this.renderer = renderer;
13398
13412
  this.el = el;
13399
13413
  this.commonStrings = commonStrings;
13414
+ this.items = items;
13415
+ this.document = document;
13400
13416
  /* reference to the enum so that template can access */
13401
13417
  this.SELECTION_TYPE = SelectionType;
13402
13418
  this.expandAnimationTrigger = false;
@@ -13426,6 +13442,24 @@ class ClrDatagridRow {
13426
13442
  }
13427
13443
  }));
13428
13444
  }
13445
+ /**
13446
+ * The default behavior in Chrome and Firefox for shift-clicking on a label is to perform text-selection.
13447
+ * This prevents our intended range-selection, because this text-selection overrides our shift-click event.
13448
+ * We need to clear the stored selection range when shift-clicking. This will override the mostly unused shift-click
13449
+ * selection browser functionality, which is inconsistently implemented in browsers anyway.
13450
+ */
13451
+ clearRanges(event) {
13452
+ if (event.shiftKey) {
13453
+ this.document.getSelection().removeAllRanges();
13454
+ // Firefox is too persistent about its text-selection behaviour. So we need to add a preventDefault();
13455
+ // We should not try to enforce this on the other browsers, though, because their toggle cycle does not get canceled by
13456
+ // the preventDefault() and they toggle the checkbox second time, effectively retrurning it to not-selected.
13457
+ if (window.navigator.userAgent.indexOf('Firefox') !== -1) {
13458
+ event.preventDefault();
13459
+ this.toggle(true);
13460
+ }
13461
+ }
13462
+ }
13429
13463
  /**
13430
13464
  * Indicates if the row is selected
13431
13465
  */
@@ -13442,6 +13476,12 @@ class ClrDatagridRow {
13442
13476
  this._selected = value;
13443
13477
  }
13444
13478
  else {
13479
+ if (value && this.selection.selectionType === SelectionType.Multi) {
13480
+ this.rangeSelect();
13481
+ }
13482
+ else {
13483
+ this.selection.rangeStart = null;
13484
+ }
13445
13485
  this.selection.setSelected(this.item, value);
13446
13486
  }
13447
13487
  }
@@ -13523,6 +13563,29 @@ class ClrDatagridRow {
13523
13563
  this.expandAnimationTrigger = !this.expandAnimationTrigger;
13524
13564
  }));
13525
13565
  }
13566
+ rangeSelect() {
13567
+ const items = this.items.displayed;
13568
+ if (!items) {
13569
+ return;
13570
+ }
13571
+ const startIx = items.indexOf(this.selection.rangeStart);
13572
+ if (this.selection.rangeStart &&
13573
+ this.selection.current.includes(this.selection.rangeStart) &&
13574
+ this.selection.shiftPressed &&
13575
+ startIx !== -1) {
13576
+ const endIx = items.indexOf(this.item);
13577
+ // Using Set to remove duplicates
13578
+ const newSelection = new Set(this.selection.current.concat(items.slice(Math.min(startIx, endIx), Math.max(startIx, endIx) + 1)));
13579
+ this.selection.clearSelection();
13580
+ this.selection.current.push(...newSelection);
13581
+ }
13582
+ else {
13583
+ // page number has changed or
13584
+ // no Shift was pressed or
13585
+ // rangeStart not yet set
13586
+ this.selection.rangeStart = this.item;
13587
+ }
13588
+ }
13526
13589
  ngOnDestroy() {
13527
13590
  this.subscriptions.forEach((sub) => sub.unsubscribe());
13528
13591
  }
@@ -13537,7 +13600,7 @@ class ClrDatagridRow {
13537
13600
  ClrDatagridRow.decorators = [
13538
13601
  { type: Component, args: [{
13539
13602
  selector: 'clr-dg-row',
13540
- template: "<!--\n We need to wrap the #rowContent in label element if we are in rowSelectionMode.\n Clicking of that wrapper label will equate to clicking on the whole row, which triggers the checkbox to toggle.\n-->\n<label class=\"datagrid-row-clickable\" *ngIf=\"selection.rowSelectionMode\">\n <clr-expandable-animation [clrExpandTrigger]=\"expandAnimationTrigger\" *ngIf=\"expand.expandable\">\n <ng-template [ngTemplateOutlet]=\"rowContent\"></ng-template>\n </clr-expandable-animation>\n <ng-template [ngTemplateOutlet]=\"rowContent\" *ngIf=\"!expand.expandable\"></ng-template>\n</label>\n\n<clr-expandable-animation\n *ngIf=\"!selection.rowSelectionMode && expand.expandable\"\n [clrExpandTrigger]=\"expandAnimationTrigger\"\n>\n <ng-template [ngTemplateOutlet]=\"rowContent\"></ng-template>\n</clr-expandable-animation>\n\n<ng-template *ngIf=\"!selection.rowSelectionMode && !expand.expandable\" [ngTemplateOutlet]=\"rowContent\"></ng-template>\n\n<!--\n We need the \"project into template\" hacks because we need this in 2 different places\n depending on whether the details replace the row or not.\n-->\n<ng-template #detail>\n <ng-content select=\"clr-dg-row-detail\"></ng-content>\n</ng-template>\n\n<ng-template #rowContent>\n <div\n role=\"row\"\n [id]=\"id\"\n class=\"datagrid-row-master datagrid-row-flex\"\n [class.datagrid-row-detail-open]=\"detailService.isRowOpen(item)\"\n >\n <div class=\"datagrid-row-sticky\">\n <!-- Sticky elements here -->\n <ng-container #stickyCells>\n <div\n *ngIf=\"selection.selectionType === SELECTION_TYPE.Multi\"\n class=\"datagrid-select datagrid-fixed-column datagrid-cell\"\n [ngClass]=\"{ 'clr-form-control-disabled': !clrDgSelectable }\"\n role=\"gridcell\"\n >\n <div class=\"clr-checkbox-wrapper\">\n <input\n type=\"checkbox\"\n [ngModel]=\"selected\"\n (ngModelChange)=\"toggle($event)\"\n [id]=\"checkboxId\"\n [attr.disabled]=\"clrDgSelectable ? null : true\"\n [attr.aria-disabled]=\"clrDgSelectable ? null : true\"\n [attr.aria-label]=\"commonStrings.keys.select\"\n />\n <!-- Usage of class clr-col-null here prevents clr-col-* classes from being added when a datagrid is wrapped inside clrForm -->\n <label [for]=\"checkboxId\" class=\"clr-control-label clr-col-null\">\n <span class=\"clr-sr-only\">{{commonStrings.keys.select}}</span>\n </label>\n </div>\n </div>\n <div\n *ngIf=\"selection.selectionType === SELECTION_TYPE.Single\"\n class=\"datagrid-select datagrid-fixed-column datagrid-cell\"\n role=\"gridcell\"\n [ngClass]=\"{ 'clr-form-control-disabled': !clrDgSelectable }\"\n >\n <!-- TODO: it would be better if in addition to the generic \"Select\" label, we could add aria-labelledby\n to label the radio by the first cell in the row (typically an id or name).\n It's pretty easy to label it with the whole row since we already have an id for it, but in most\n cases the row is far too long to serve as a label, the screenreader reads every single cell content. -->\n <input\n type=\"radio\"\n clrRadio\n [id]=\"radioId\"\n [name]=\"selection.id + '-radio'\"\n [value]=\"item\"\n [(ngModel)]=\"selection.currentSingle\"\n [checked]=\"selection.currentSingle === item\"\n [attr.disabled]=\"clrDgSelectable ? null : true\"\n [attr.aria-disabled]=\"clrDgSelectable ? null : true\"\n [attr.aria-label]=\"commonStrings.keys.select\"\n />\n </div>\n <div\n *ngIf=\"rowActionService.hasActionableRow\"\n class=\"datagrid-row-actions datagrid-fixed-column datagrid-cell\"\n role=\"gridcell\"\n >\n <ng-content select=\"clr-dg-action-overflow\"></ng-content>\n </div>\n <div\n *ngIf=\"globalExpandable.hasExpandableRow\"\n class=\"datagrid-expandable-caret datagrid-fixed-column datagrid-cell\"\n role=\"gridcell\"\n >\n <ng-container *ngIf=\"expand.expandable\">\n <button\n *ngIf=\"!expand.loading\"\n (click)=\"toggleExpand()\"\n type=\"button\"\n class=\"datagrid-expandable-caret-button\"\n [attr.aria-expanded]=\"expand.expanded\"\n [attr.aria-label]=\"expand.expanded ? clrDgDetailCloseLabel : clrDgDetailOpenLabel\"\n [attr.aria-controls]=\"expandableId\"\n >\n <cds-icon\n shape=\"angle\"\n class=\"datagrid-expandable-caret-icon\"\n [attr.direction]=\"expand.expanded ? 'down' : 'right'\"\n [attr.title]=\"expand.expanded ? commonStrings.keys.collapse : commonStrings.keys.expand\"\n ></cds-icon>\n </button>\n <clr-spinner *ngIf=\"expand.loading\" clrSmall>{{ commonStrings.keys.loading }}</clr-spinner>\n </ng-container>\n </div>\n <div *ngIf=\"detailService.enabled\" class=\"datagrid-detail-caret datagrid-fixed-column datagrid-cell\">\n <button\n (click)=\"detailService.toggle(item, detailButton)\"\n type=\"button\"\n #detailButton\n class=\"datagrid-detail-caret-button\"\n [class.is-open]=\"detailService.isRowOpen(item)\"\n [attr.aria-label]=\"detailService.isOpen ? clrDgDetailCloseLabel : clrDgDetailOpenLabel\"\n [attr.aria-expanded]=\"detailService.isOpen\"\n [attr.aria-controls]=\"detailService.id\"\n aria-haspopup=\"dialog\"\n >\n <cds-icon\n shape=\"angle-double\"\n [attr.direction]=\"detailService.isRowOpen(item) ? 'left' : 'right'\"\n class=\"datagrid-detail-caret-icon\"\n [attr.title]=\"detailService.isRowOpen(item) ? commonStrings.keys.close: commonStrings.keys.open\"\n ></cds-icon>\n </button>\n </div>\n </ng-container>\n <!-- placeholder for projecting other sticky cells as pinned-->\n </div>\n <div class=\"datagrid-row-scrollable\" [ngClass]=\"{'is-replaced': replaced && expanded}\">\n <div class=\"datagrid-scrolling-cells\">\n <ng-content select=\"clr-dg-cell\"></ng-content>\n <ng-container #scrollableCells></ng-container>\n </div>\n <!-- details here when replace, re-visit when sticky container is used for pinned cells -->\n <ng-template *ngIf=\"replaced && !expand.loading\" [ngTemplateOutlet]=\"detail\"></ng-template>\n <ng-template *ngIf=\"!replaced && !expand.loading\" [ngTemplateOutlet]=\"detail\"></ng-template>\n </div>\n </div>\n</ng-template>\n\n<ng-container #calculatedCells></ng-container>\n",
13603
+ template: "<!--\n We need to wrap the #rowContent in label element if we are in rowSelectionMode.\n Clicking of that wrapper label will equate to clicking on the whole row, which triggers the checkbox to toggle.\n-->\n<label class=\"datagrid-row-clickable\" *ngIf=\"selection.rowSelectionMode\" (mousedown)=\"clearRanges($event)\">\n <clr-expandable-animation [clrExpandTrigger]=\"expandAnimationTrigger\" *ngIf=\"expand.expandable\">\n <ng-template [ngTemplateOutlet]=\"rowContent\"></ng-template>\n </clr-expandable-animation>\n <ng-template [ngTemplateOutlet]=\"rowContent\" *ngIf=\"!expand.expandable\"></ng-template>\n</label>\n\n<clr-expandable-animation\n *ngIf=\"!selection.rowSelectionMode && expand.expandable\"\n [clrExpandTrigger]=\"expandAnimationTrigger\"\n>\n <ng-template [ngTemplateOutlet]=\"rowContent\"></ng-template>\n</clr-expandable-animation>\n\n<ng-template *ngIf=\"!selection.rowSelectionMode && !expand.expandable\" [ngTemplateOutlet]=\"rowContent\"></ng-template>\n\n<!--\n We need the \"project into template\" hacks because we need this in 2 different places\n depending on whether the details replace the row or not.\n-->\n<ng-template #detail>\n <ng-content select=\"clr-dg-row-detail\"></ng-content>\n</ng-template>\n\n<ng-template #rowContent>\n <div\n role=\"row\"\n [id]=\"id\"\n class=\"datagrid-row-master datagrid-row-flex\"\n [class.datagrid-row-detail-open]=\"detailService.isRowOpen(item)\"\n >\n <div class=\"datagrid-row-sticky\">\n <!-- Sticky elements here -->\n <ng-container #stickyCells>\n <div\n *ngIf=\"selection.selectionType === SELECTION_TYPE.Multi\"\n class=\"datagrid-select datagrid-fixed-column datagrid-cell\"\n [ngClass]=\"{ 'clr-form-control-disabled': !clrDgSelectable }\"\n role=\"gridcell\"\n >\n <div class=\"clr-checkbox-wrapper\">\n <input\n type=\"checkbox\"\n [ngModel]=\"selected\"\n (ngModelChange)=\"toggle($event)\"\n [id]=\"checkboxId\"\n [attr.disabled]=\"clrDgSelectable ? null : true\"\n [attr.aria-disabled]=\"clrDgSelectable ? null : true\"\n [attr.aria-label]=\"commonStrings.keys.select\"\n />\n <!-- Usage of class clr-col-null here prevents clr-col-* classes from being added when a datagrid is wrapped inside clrForm -->\n <label [for]=\"checkboxId\" class=\"clr-control-label clr-col-null\" (click)=\"clearRanges($event)\">\n <span class=\"clr-sr-only\">{{commonStrings.keys.select}}</span>\n </label>\n </div>\n </div>\n <div\n *ngIf=\"selection.selectionType === SELECTION_TYPE.Single\"\n class=\"datagrid-select datagrid-fixed-column datagrid-cell\"\n role=\"gridcell\"\n [ngClass]=\"{ 'clr-form-control-disabled': !clrDgSelectable }\"\n >\n <!-- TODO: it would be better if in addition to the generic \"Select\" label, we could add aria-labelledby\n to label the radio by the first cell in the row (typically an id or name).\n It's pretty easy to label it with the whole row since we already have an id for it, but in most\n cases the row is far too long to serve as a label, the screenreader reads every single cell content. -->\n <input\n type=\"radio\"\n clrRadio\n [id]=\"radioId\"\n [name]=\"selection.id + '-radio'\"\n [value]=\"item\"\n [(ngModel)]=\"selection.currentSingle\"\n [checked]=\"selection.currentSingle === item\"\n [attr.disabled]=\"clrDgSelectable ? null : true\"\n [attr.aria-disabled]=\"clrDgSelectable ? null : true\"\n [attr.aria-label]=\"commonStrings.keys.select\"\n />\n </div>\n <div\n *ngIf=\"rowActionService.hasActionableRow\"\n class=\"datagrid-row-actions datagrid-fixed-column datagrid-cell\"\n role=\"gridcell\"\n >\n <ng-content select=\"clr-dg-action-overflow\"></ng-content>\n </div>\n <div\n *ngIf=\"globalExpandable.hasExpandableRow\"\n class=\"datagrid-expandable-caret datagrid-fixed-column datagrid-cell\"\n role=\"gridcell\"\n >\n <ng-container *ngIf=\"expand.expandable\">\n <button\n *ngIf=\"!expand.loading\"\n (click)=\"toggleExpand()\"\n type=\"button\"\n class=\"datagrid-expandable-caret-button\"\n [attr.aria-expanded]=\"expand.expanded\"\n [attr.aria-label]=\"expand.expanded ? clrDgDetailCloseLabel : clrDgDetailOpenLabel\"\n [attr.aria-controls]=\"expandableId\"\n >\n <cds-icon\n shape=\"angle\"\n class=\"datagrid-expandable-caret-icon\"\n [attr.direction]=\"expand.expanded ? 'down' : 'right'\"\n [attr.title]=\"expand.expanded ? commonStrings.keys.collapse : commonStrings.keys.expand\"\n ></cds-icon>\n </button>\n <clr-spinner *ngIf=\"expand.loading\" clrSmall>{{ commonStrings.keys.loading }}</clr-spinner>\n </ng-container>\n </div>\n <div *ngIf=\"detailService.enabled\" class=\"datagrid-detail-caret datagrid-fixed-column datagrid-cell\">\n <button\n (click)=\"detailService.toggle(item, detailButton)\"\n type=\"button\"\n #detailButton\n class=\"datagrid-detail-caret-button\"\n [class.is-open]=\"detailService.isRowOpen(item)\"\n [attr.aria-label]=\"detailService.isOpen ? clrDgDetailCloseLabel : clrDgDetailOpenLabel\"\n [attr.aria-expanded]=\"detailService.isOpen\"\n [attr.aria-controls]=\"detailService.id\"\n aria-haspopup=\"dialog\"\n >\n <cds-icon\n shape=\"angle-double\"\n [attr.direction]=\"detailService.isRowOpen(item) ? 'left' : 'right'\"\n class=\"datagrid-detail-caret-icon\"\n [attr.title]=\"detailService.isRowOpen(item) ? commonStrings.keys.close: commonStrings.keys.open\"\n ></cds-icon>\n </button>\n </div>\n </ng-container>\n <!-- placeholder for projecting other sticky cells as pinned-->\n </div>\n <div class=\"datagrid-row-scrollable\" [ngClass]=\"{'is-replaced': replaced && expanded}\">\n <div class=\"datagrid-scrolling-cells\">\n <ng-content select=\"clr-dg-cell\"></ng-content>\n <ng-container #scrollableCells></ng-container>\n </div>\n <!-- details here when replace, re-visit when sticky container is used for pinned cells -->\n <ng-template *ngIf=\"replaced && !expand.loading\" [ngTemplateOutlet]=\"detail\"></ng-template>\n <ng-template *ngIf=\"!replaced && !expand.loading\" [ngTemplateOutlet]=\"detail\"></ng-template>\n </div>\n </div>\n</ng-template>\n\n<ng-container #calculatedCells></ng-container>\n",
13541
13604
  host: {
13542
13605
  '[class.datagrid-row]': 'true',
13543
13606
  '[class.datagrid-selected]': 'selected',
@@ -13561,7 +13624,9 @@ ClrDatagridRow.ctorParameters = () => [
13561
13624
  { type: ViewContainerRef },
13562
13625
  { type: Renderer2 },
13563
13626
  { type: ElementRef },
13564
- { type: ClrCommonStringsService }
13627
+ { type: ClrCommonStringsService },
13628
+ { type: Items },
13629
+ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
13565
13630
  ];
13566
13631
  ClrDatagridRow.propDecorators = {
13567
13632
  expandAnimation: [{ type: ViewChild, args: [ClrExpandableAnimation,] }],
@@ -13932,7 +13997,7 @@ KeyNavigationGridController.ctorParameters = () => [
13932
13997
  * The full license information can be found in LICENSE in the root directory of this project.
13933
13998
  */
13934
13999
  class ClrDatagrid {
13935
- constructor(organizer, items, expandableRows, selection, rowActionService, stateProvider, displayMode, renderer, detailService, datagridId, el, page, commonStrings, columnsService, keyNavigation) {
14000
+ constructor(organizer, items, expandableRows, selection, rowActionService, stateProvider, displayMode, renderer, detailService, datagridId, document, el, page, commonStrings, columnsService, keyNavigation, zone) {
13936
14001
  this.organizer = organizer;
13937
14002
  this.items = items;
13938
14003
  this.expandableRows = expandableRows;
@@ -13942,11 +14007,13 @@ class ClrDatagrid {
13942
14007
  this.displayMode = displayMode;
13943
14008
  this.renderer = renderer;
13944
14009
  this.detailService = detailService;
14010
+ this.document = document;
13945
14011
  this.el = el;
13946
14012
  this.page = page;
13947
14013
  this.commonStrings = commonStrings;
13948
14014
  this.columnsService = columnsService;
13949
14015
  this.keyNavigation = keyNavigation;
14016
+ this.zone = zone;
13950
14017
  /* reference to the enum so that template can access */
13951
14018
  this.SELECTION_TYPE = SelectionType;
13952
14019
  /**
@@ -14131,6 +14198,19 @@ class ClrDatagrid {
14131
14198
  });
14132
14199
  }
14133
14200
  }));
14201
+ // We need to preserve shift state, so it can be used on selection change, regardless of the input event
14202
+ // that triggered the change. This helps us to easily resolve the k/b only case together with the mouse selection case.
14203
+ this.zone.runOutsideAngular(() => {
14204
+ this._subscriptions.push(fromEvent(this.document.body, 'keydown').subscribe((event) => {
14205
+ if (event.key === 'Shift') {
14206
+ this.selection.shiftPressed = true;
14207
+ }
14208
+ }), fromEvent(this.document.body, 'keyup').subscribe((event) => {
14209
+ if (event.key === 'Shift') {
14210
+ this.selection.shiftPressed = false;
14211
+ }
14212
+ }));
14213
+ });
14134
14214
  }
14135
14215
  ngOnDestroy() {
14136
14216
  this._subscriptions.forEach((sub) => sub.unsubscribe());
@@ -14178,11 +14258,13 @@ ClrDatagrid.ctorParameters = () => [
14178
14258
  { type: Renderer2 },
14179
14259
  { type: DetailService },
14180
14260
  { type: String, decorators: [{ type: Inject, args: [UNIQUE_ID,] }] },
14261
+ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
14181
14262
  { type: ElementRef },
14182
14263
  { type: Page },
14183
14264
  { type: ClrCommonStringsService },
14184
14265
  { type: ColumnsService },
14185
- { type: KeyNavigationGridController }
14266
+ { type: KeyNavigationGridController },
14267
+ { type: NgZone }
14186
14268
  ];
14187
14269
  ClrDatagrid.propDecorators = {
14188
14270
  loading: [{ type: Input, args: ['clrDgLoading',] }],
@@ -15138,6 +15220,7 @@ ClrDatagridItemsTrackBy.propDecorators = {
15138
15220
  class ClrDatagridPageSize {
15139
15221
  constructor(page) {
15140
15222
  this.page = page;
15223
+ this.pageSizeOptionsId = uniqueIdFactory();
15141
15224
  }
15142
15225
  ngOnInit() {
15143
15226
  if (!this.pageSizeOptions || this.pageSizeOptions.length === 0) {
@@ -15151,7 +15234,7 @@ ClrDatagridPageSize.decorators = [
15151
15234
  template: `
15152
15235
  <ng-content></ng-content>
15153
15236
  <div class="clr-select-wrapper">
15154
- <select [class.clr-page-size-select]="true" [(ngModel)]="page.size">
15237
+ <select [id]="pageSizeOptionsId" [class.clr-page-size-select]="true" [(ngModel)]="page.size">
15155
15238
  <option *ngFor="let option of pageSizeOptions" [ngValue]="option">{{ option }}</option>
15156
15239
  </select>
15157
15240
  </div>
@@ -15162,7 +15245,8 @@ ClrDatagridPageSize.ctorParameters = () => [
15162
15245
  { type: Page }
15163
15246
  ];
15164
15247
  ClrDatagridPageSize.propDecorators = {
15165
- pageSizeOptions: [{ type: Input, args: ['clrPageSizeOptions',] }]
15248
+ pageSizeOptions: [{ type: Input, args: ['clrPageSizeOptions',] }],
15249
+ pageSizeOptionsId: [{ type: Input, args: ['clrPageSizeOptionsId',] }]
15166
15250
  };
15167
15251
 
15168
15252
  /*