@progress/kendo-angular-pivotgrid 16.6.0-develop.2 → 16.6.0-develop.4

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.
@@ -278,19 +278,19 @@ const matchAriaAttributes = (wrapper) => {
278
278
  const firstColHeaderRowCellsIds = Array.from(firstColHeadersRow?.children).map(el => el.getAttribute('id')).join(' ');
279
279
  firstColHeadersRow.setAttribute('aria-owns', `${emptyCell.getAttribute('id')} ${firstColHeaderRowCellsIds}`);
280
280
  rowHeaderRows.forEach((row, index) => {
281
- const valueCellsIds = filterAndMap(Array.from(valueTableCells), c => c.getAttribute('id').split('-')[4] === (index + 1).toString(), c => c.getAttribute('id'));
281
+ const valueCellsIds = filterAndMap(Array.from(valueTableCells), c => c.getAttribute('id')?.split('-')[4] === (index + 1).toString(), c => c.getAttribute('id'));
282
282
  row.setAttribute('aria-owns', valueCellsIds.join(' '));
283
283
  });
284
284
  valueTableCells.forEach(cell => {
285
- const cellColIndex = +cell.getAttribute('id').split('-')[5];
285
+ const cellColIndex = +cell.getAttribute('id')?.split('-')[5];
286
286
  const colHeaderCellsIds = filterAndMap(Array.from(colHeaderCells), c => {
287
- const headerCellColIndex = +c.getAttribute('id').split('-')[5];
287
+ const headerCellColIndex = +c.getAttribute('id')?.split('-')[5];
288
288
  const headerCellColspan = +c.getAttribute('colspan');
289
289
  const colIndexIsEqual = cellColIndex === headerCellColIndex;
290
- const cellColIndexIsWithinHeaderCellRange = headerCellColspan > 1 && (headerCellColIndex + headerCellColspan - 1 >= cellColIndex);
290
+ const cellColIndexIsWithinHeaderCellRange = headerCellColIndex < cellColIndex && headerCellColspan > 1 && (headerCellColIndex + headerCellColspan - 1 >= cellColIndex);
291
291
  return colIndexIsEqual || cellColIndexIsWithinHeaderCellRange;
292
292
  }, c => c.getAttribute('id'));
293
- cell.setAttribute('aria-describedby', colHeaderCellsIds.join(' '));
293
+ colHeaderCellsIds.length && cell.setAttribute('aria-describedby', colHeaderCellsIds.join(' '));
294
294
  });
295
295
  };
296
296
  /**
@@ -365,6 +365,31 @@ const swapItems = (arr, i1, i2) => {
365
365
  arr[i1] = arr[i2];
366
366
  arr[i2] = temp;
367
367
  };
368
+ /**
369
+ * @hidden
370
+ */
371
+ const isVisible = (el, container, offsetY, rtl) => {
372
+ const elTop = el.offsetTop;
373
+ const elBottom = elTop + el.clientHeight;
374
+ let rect;
375
+ let containerRect;
376
+ if (rtl) {
377
+ rect = el.getBoundingClientRect();
378
+ containerRect = container.getBoundingClientRect();
379
+ }
380
+ const elLeft = rtl ? rect.left : el.offsetLeft;
381
+ const elRight = rtl ? rect.right : elLeft + el.clientWidth;
382
+ const containerTop = container.scrollTop;
383
+ const containerBottom = containerTop + container.clientHeight;
384
+ const containerLeft = rtl ? containerRect.left : container.scrollLeft;
385
+ const containerRight = rtl ? containerRect.right : containerLeft + container.clientWidth;
386
+ const visibleY = elTop >= containerTop - offsetY && elBottom <= containerBottom - offsetY;
387
+ const visibleX = rtl ? elRight <= containerRight && elLeft >= containerLeft : elLeft >= containerLeft && elRight <= containerRight;
388
+ return {
389
+ visibleX,
390
+ visibleY
391
+ };
392
+ };
368
393
 
369
394
  /**
370
395
  * @hidden
@@ -3346,8 +3371,8 @@ const packageMetadata = {
3346
3371
  name: '@progress/kendo-angular-pivotgrid',
3347
3372
  productName: 'Kendo UI for Angular',
3348
3373
  productCodes: ['KENDOUIANGULAR', 'KENDOUICOMPLETE'],
3349
- publishDate: 1721847262,
3350
- version: '16.6.0-develop.2',
3374
+ publishDate: 1722517399,
3375
+ version: '16.6.0-develop.4',
3351
3376
  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'
3352
3377
  };
3353
3378
 
@@ -3498,6 +3523,117 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
3498
3523
  }]
3499
3524
  }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
3500
3525
 
3526
+ /**
3527
+ * @hidden
3528
+ */
3529
+ class ScrollableTable {
3530
+ constructor(element, handlers, options) {
3531
+ this.element = element;
3532
+ this.handlers = handlers;
3533
+ this.options = options;
3534
+ this.startRow = 0;
3535
+ this.startCol = 0;
3536
+ this.lastKnownScrollPosition = { top: 0, left: 0 };
3537
+ this.offsetFirst = 0;
3538
+ this.scrollHandler = (e) => {
3539
+ const verticalDir = this.element.scrollTop - this.lastKnownScrollPosition.top;
3540
+ const horizontalDir = Math.abs(this.element.scrollLeft) - this.lastKnownScrollPosition.left;
3541
+ if (this.options.rowVirtualization) {
3542
+ if (verticalDir > 0) {
3543
+ if (this.element.scrollTop > (this.renderedRows * this.options.itemHeight + this.offsetFirst - this.rect.height)) {
3544
+ this.startRow = Math.floor(this.element.scrollTop / this.options.itemHeight);
3545
+ this.rowVirtualizationUpdate();
3546
+ }
3547
+ }
3548
+ else {
3549
+ if (this.element.scrollTop <= this.offsetFirst) {
3550
+ this.startRow = Math.max(0, Math.ceil(this.element.scrollTop / this.options.itemHeight) - Math.ceil(this.options.renderedRows / 3));
3551
+ this.rowVirtualizationUpdate();
3552
+ }
3553
+ }
3554
+ }
3555
+ if (this.options.columnVirtualization) {
3556
+ if (horizontalDir > 0) {
3557
+ if (Math.abs(this.element.scrollLeft) - (Math.max(this.startCol - 1, 0) * (this.options.colWidth || 200)) > (this.options.colWidth || 200)) {
3558
+ this.startCol = Math.min(Math.max(Math.floor(Math.abs(this.element.scrollLeft) / this.options.itemWidth) - 1, 0), this.totalCols - this.renderedCols);
3559
+ this.handlers.onScroll();
3560
+ }
3561
+ }
3562
+ else {
3563
+ if (Math.abs(this.element.scrollLeft) <= (this.startCol + 1) * (this.options.colWidth || 200)) {
3564
+ this.startCol = Math.min(Math.max(Math.floor(Math.abs(this.element.scrollLeft) / this.options.itemWidth) - 1, 0), this.totalCols - this.renderedCols);
3565
+ this.handlers.onScroll();
3566
+ }
3567
+ }
3568
+ }
3569
+ this.lastKnownScrollPosition = {
3570
+ top: this.element.scrollTop,
3571
+ left: Math.abs(this.element.scrollLeft)
3572
+ };
3573
+ };
3574
+ this.scrollEndHandler = () => {
3575
+ this.handlers.onScrollEnd();
3576
+ };
3577
+ this.initialize();
3578
+ }
3579
+ onNewData(recalculateSize = false) {
3580
+ this.offsetFirst = this.startRow * this.options.itemHeight;
3581
+ this.renderedRows = Math.min(this.options.renderedRows || Math.ceil(this.visibleRows * 3), this.total);
3582
+ this.endRow = this.startRow + this.renderedRows;
3583
+ this.renderedCols = Math.min(this.options.renderedCols || Math.ceil(this.visibleCols * 1.3), this.totalCols);
3584
+ this.element.querySelector('table').style.transform = `translateY(${this.offsetFirst}px)`;
3585
+ recalculateSize && this.recalculateSize();
3586
+ }
3587
+ destroy() {
3588
+ this.element.removeEventListener('scroll', this.scrollHandler);
3589
+ this.element.removeEventListener('scrollend', this.scrollEndHandler);
3590
+ this.element.removeChild(this.stretcher);
3591
+ }
3592
+ initialize() {
3593
+ this.rtl = this.options.rtl;
3594
+ this.rect = this.element.getBoundingClientRect();
3595
+ // visible rows and cols
3596
+ this.visibleRows = Math.ceil(this.rect.height / this.options.itemHeight);
3597
+ this.visibleCols = Math.ceil(this.rect.width / this.options.itemWidth);
3598
+ // current totals
3599
+ this.total = this.options.total;
3600
+ this.totalCols = this.options.totalCols;
3601
+ const totalHeight = this.total * this.options.itemHeight;
3602
+ const totalWidth = this.totalCols * this.options.itemWidth;
3603
+ // "page" size (rows and cols)
3604
+ this.renderedRows = Math.min(this.options.renderedRows || Math.ceil(this.visibleRows * 3), this.total);
3605
+ this.renderedCols = Math.min(this.options.renderedCols || Math.ceil(this.visibleCols * 1.3), this.totalCols);
3606
+ // start and end row/col
3607
+ this.startRow = 0;
3608
+ this.startCol = 0;
3609
+ this.endRow = this.startRow + this.renderedRows;
3610
+ this.endCol = this.startCol + this.renderedCols;
3611
+ // element that ensures correct scrolling dimensions of the container
3612
+ this.stretcher = document.createElement('DIV');
3613
+ this.stretcher.style.height = `${totalHeight}px`;
3614
+ this.stretcher.style.width = `${totalWidth}px`;
3615
+ this.element.appendChild(this.stretcher);
3616
+ this.element.addEventListener('scroll', this.scrollHandler);
3617
+ this.element.addEventListener('scrollend', this.scrollEndHandler);
3618
+ }
3619
+ recalculateSize() {
3620
+ const totalHeight = this.total * this.options.itemHeight;
3621
+ const totalWidth = this.totalCols * this.options.itemWidth;
3622
+ this.stretcher.style.height = `${totalHeight}px`;
3623
+ this.stretcher.style.width = `${totalWidth}px`;
3624
+ this.rect = this.element.getBoundingClientRect();
3625
+ // visible rows and cols
3626
+ this.visibleRows = Math.ceil(this.rect.height / this.options.itemHeight);
3627
+ this.visibleCols = Math.ceil(this.rect.width / this.options.itemWidth);
3628
+ }
3629
+ rowVirtualizationUpdate() {
3630
+ this.endRow = Math.min(this.startRow + this.renderedRows, this.total);
3631
+ this.offsetFirst = this.startRow * this.options.itemHeight;
3632
+ this.element.querySelector('table').style.transform = `translateY(${this.offsetFirst}px)`;
3633
+ this.handlers.onScroll();
3634
+ }
3635
+ }
3636
+
3501
3637
  /**
3502
3638
  * @hidden
3503
3639
  */
@@ -3696,42 +3832,201 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
3696
3832
  type: Input
3697
3833
  }] } });
3698
3834
 
3835
+ /**
3836
+ * @hidden
3837
+ */
3838
+ class PivotGridScrollService {
3839
+ constructor() {
3840
+ this.virtualScrolling = false;
3841
+ }
3842
+ }
3843
+ PivotGridScrollService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridScrollService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3844
+ PivotGridScrollService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridScrollService });
3845
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridScrollService, decorators: [{
3846
+ type: Injectable
3847
+ }] });
3848
+
3699
3849
  /**
3700
3850
  * @hidden
3701
3851
  */
3702
3852
  class PivotGridTableComponent {
3703
- constructor(dataService) {
3853
+ constructor(host, dataService, localization, pivotGrid, zone, scrollService) {
3854
+ this.host = host;
3704
3855
  this.dataService = dataService;
3705
- this.dataChangeSubs = new Subscription();
3856
+ this.localization = localization;
3857
+ this.pivotGrid = pivotGrid;
3858
+ this.zone = zone;
3859
+ this.scrollService = scrollService;
3860
+ this.startRowIndex = 0;
3861
+ this.startColIndex = 0;
3862
+ this.rtl = false;
3863
+ this.subs = new Subscription();
3864
+ this.colsUpdateCallback = (cols) => {
3865
+ this.renderedCols = Math.min(cols.length, this.scrollableSettings?.columns);
3866
+ this.renderedCols && this.scrollable && (this.scrollable.totalCols = cols.length);
3867
+ (this.scrollableSettings && this.scrollableSettings.type !== 'row') && this.scrollable?.onNewData(true);
3868
+ this.headerItems = cols;
3869
+ isDocumentAvailable() && !this.scrollable && this.tableType === 'values' && (this.columnVirtualization || this.rowVirtualization) && this.initScrollable();
3870
+ };
3871
+ this.initScrollable = () => {
3872
+ this.scrollable = new ScrollableTable(this.host.nativeElement, {
3873
+ onScroll: () => {
3874
+ this.startRowIndex = this.scrollable.startRow;
3875
+ this.startColIndex = this.scrollable.startCol;
3876
+ this.renderedRows = this.rows.slice(this.startRowIndex, this.startRowIndex + this.scrollableSettings.rows);
3877
+ this.scrollable.renderedRows = this.renderedRows.length;
3878
+ this.scrollable.renderedCols = this.renderedCols;
3879
+ },
3880
+ onScrollEnd: () => {
3881
+ matchAriaAttributes(this.host.nativeElement.closest('.k-pivotgrid'));
3882
+ }
3883
+ }, {
3884
+ itemHeight: this.scrollableSettings.rowHeight,
3885
+ itemWidth: this.colWidth || 200,
3886
+ total: this.totalRows,
3887
+ totalCols: this.headerItems.length,
3888
+ renderedRows: this.scrollableSettings.rows,
3889
+ renderedCols: this.scrollableSettings.columns,
3890
+ columnVirtualization: this.columnVirtualization,
3891
+ rowVirtualization: this.rowVirtualization,
3892
+ rtl: this.rtl
3893
+ });
3894
+ };
3895
+ this.subs.add(this.localization.changes.subscribe(({ rtl }) => {
3896
+ this.rtl = rtl;
3897
+ this.scrollable && (this.scrollable.rtl = rtl);
3898
+ }));
3706
3899
  }
3707
3900
  get pivotGridId() {
3708
3901
  return `kendo-pivotgrid-${this.dataService.pivotGridId}-`;
3709
3902
  }
3903
+ get columnVirtualization() {
3904
+ return this.scrollableSettings?.type && this.scrollableSettings?.type !== 'row';
3905
+ }
3906
+ get rowVirtualization() {
3907
+ return this.scrollableSettings?.type && this.scrollableSettings?.type !== 'column';
3908
+ }
3710
3909
  ngOnInit() {
3711
- this.dataChangeSubs.add(this.dataService[`${this.tableType}Rows`].subscribe(rows => this.rows = rows));
3712
- this.dataChangeSubs.add(this.tableType === 'values' ?
3713
- this.dataService.columnHeaderCols.subscribe(cols => this.headerItems = cols) :
3714
- this.dataService[`${this.tableType}Cols`].subscribe(cols => this.headerItems = cols));
3910
+ this.subs.add(this.dataService[`${this.tableType}Rows`].subscribe(rows => {
3911
+ this.rows = rows;
3912
+ this.renderedRows = this.scrollableSettings ? rows.slice(this.startRowIndex, this.startRowIndex + this.scrollableSettings.rows) : rows;
3913
+ this.totalRows && this.totalRows !== rows.length && this.scrollable && (this.scrollable.total = rows.length);
3914
+ this.scrollable && this.scrollable.onNewData(this.totalRows && this.totalRows !== rows.length);
3915
+ this.totalRows = rows.length;
3916
+ }));
3917
+ this.subs.add(this.tableType === 'values' ?
3918
+ this.dataService.columnHeaderCols.subscribe(this.colsUpdateCallback) :
3919
+ this.dataService[`${this.tableType}Cols`].subscribe(this.colsUpdateCallback));
3920
+ }
3921
+ ngAfterViewInit() {
3922
+ if (isDocumentAvailable() && this.scrollService.virtualScrolling) {
3923
+ this.initScrollableKeyboardNavigation();
3924
+ }
3715
3925
  }
3716
3926
  ngOnDestroy() {
3717
- this.dataChangeSubs.unsubscribe();
3927
+ this.subs.unsubscribe();
3928
+ this.scrollable?.destroy();
3929
+ }
3930
+ initScrollableKeyboardNavigation() {
3931
+ this.host.nativeElement.addEventListener('keydown', (e) => {
3932
+ if (this.tableType === 'values' && e.target.tagName === 'TD') {
3933
+ e.stopImmediatePropagation();
3934
+ e.preventDefault();
3935
+ if (e.keyCode === Keys.ArrowLeft) {
3936
+ const id = e.target.getAttribute('id');
3937
+ if (id.split('-')[5] === '1') {
3938
+ const target = document.querySelector(`tr[aria-owns*="${id}"]`);
3939
+ this.pivotGrid.navigation.focusElement(target.lastElementChild, e.target);
3940
+ }
3941
+ else {
3942
+ this.pivotGrid.navigation.focusElement(e.target.previousElementSibling, e.target);
3943
+ if (!isVisible(e.target.previousElementSibling, this.host.nativeElement, this.scrollable.offsetFirst, this.rtl).visibleX) {
3944
+ e.target.previousElementSibling.scrollIntoView({ behavior: 'auto', block: 'nearest', inline: 'start' });
3945
+ }
3946
+ }
3947
+ }
3948
+ else if (e.keyCode === Keys.ArrowRight) {
3949
+ const id = e.target.getAttribute('id');
3950
+ if (id.split('-')[5] !== this.headerItems.length.toString()) {
3951
+ this.pivotGrid.navigation.focusElement(e.target.nextElementSibling, e.target);
3952
+ if (!isVisible(e.target.nextElementSibling, this.host.nativeElement, this.scrollable.offsetFirst, this.rtl).visibleX) {
3953
+ e.target.nextElementSibling.scrollIntoView({ behavior: 'auto', block: 'nearest', inline: 'start' });
3954
+ }
3955
+ }
3956
+ }
3957
+ else if (e.keyCode === Keys.ArrowUp) {
3958
+ const id = e.target.getAttribute('id');
3959
+ if (id.split('-')[4] === '1') {
3960
+ const target = document.getElementById(e.target.getAttribute('aria-describedby').split(' ').pop());
3961
+ this.pivotGrid.navigation.focusElement(target, e.target);
3962
+ }
3963
+ else {
3964
+ const index = Array.from(e.target.parentElement.children).findIndex(el => el === e.target);
3965
+ const elementToFocus = e.target.parentElement.previousElementSibling.children[index];
3966
+ this.pivotGrid.navigation.focusElement(elementToFocus, e.target);
3967
+ if (!isVisible(elementToFocus, this.host.nativeElement, this.scrollable.offsetFirst, this.rtl).visibleY) {
3968
+ elementToFocus.scrollIntoView();
3969
+ }
3970
+ }
3971
+ }
3972
+ else if (e.keyCode === Keys.ArrowDown) {
3973
+ const id = e.target.getAttribute('id');
3974
+ if (id.split('-')[4] !== this.totalRows.toString()) {
3975
+ const index = Array.from(e.target.parentElement.children).findIndex(el => el === e.target);
3976
+ const elementToFocus = e.target.parentElement.nextElementSibling.children[index];
3977
+ this.pivotGrid.navigation.focusElement(elementToFocus, e.target);
3978
+ if (!isVisible(elementToFocus, this.host.nativeElement, this.scrollable.offsetFirst, this.rtl).visibleY) {
3979
+ elementToFocus.scrollIntoView(false);
3980
+ }
3981
+ }
3982
+ }
3983
+ }
3984
+ if (this.tableType === 'rowHeader' && e.target.tagName === 'TH' && e.keyCode === Keys.ArrowRight) {
3985
+ if (e.target.matches(':last-child')) {
3986
+ e.stopImmediatePropagation();
3987
+ e.preventDefault();
3988
+ const valuesContainer = this.host.nativeElement.nextElementSibling;
3989
+ valuesContainer.scrollLeft = this.rtl ? valuesContainer.scrollWidth : 0;
3990
+ this.zone.runOutsideAngular(() => setTimeout(() => {
3991
+ const elementToFocusId = e.target.parentElement.getAttribute('aria-owns').split(' ')[0];
3992
+ const elementToFocus = document.getElementById(elementToFocusId);
3993
+ this.pivotGrid.navigation.focusElement(elementToFocus, e.target);
3994
+ }));
3995
+ }
3996
+ }
3997
+ if (this.tableType === 'columnHeader' && e.target.tagName === 'TH' && e.keyCode === Keys.ArrowDown) {
3998
+ if (e.target.parentElement.matches(':last-child')) {
3999
+ e.stopImmediatePropagation();
4000
+ e.preventDefault();
4001
+ const valuesContainer = this.host.nativeElement.nextElementSibling.nextElementSibling;
4002
+ valuesContainer.scrollTop = 0;
4003
+ this.zone.runOutsideAngular(() => setTimeout(() => {
4004
+ const elementToFocus = valuesContainer.querySelector(`td[aria-describedby*="${e.target.getAttribute('id')}"]`);
4005
+ this.pivotGrid.navigation.focusElement(elementToFocus, e.target);
4006
+ }));
4007
+ }
4008
+ }
4009
+ }, true);
3718
4010
  }
3719
4011
  }
3720
- PivotGridTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridTableComponent, deps: [{ token: PivotGridDataService }], target: i0.ɵɵFactoryTarget.Component });
3721
- PivotGridTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: PivotGridTableComponent, isStandalone: true, selector: "kendo-pivotgrid-table", inputs: { tableType: "tableType", colWidth: "colWidth", customCellTemplate: "customCellTemplate", valueCellTemplate: "valueCellTemplate", rowHeaderCellTemplate: "rowHeaderCellTemplate", columnHeaderCellTemplate: "columnHeaderCellTemplate" }, ngImport: i0, template: `
4012
+ PivotGridTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridTableComponent, deps: [{ token: i0.ElementRef }, { token: PivotGridDataService }, { token: i1$1.LocalizationService }, { token: PivotGridComponent }, { token: i0.NgZone }, { token: PivotGridScrollService }], target: i0.ɵɵFactoryTarget.Component });
4013
+ PivotGridTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: PivotGridTableComponent, isStandalone: true, selector: "kendo-pivotgrid-table", inputs: { tableType: "tableType", colWidth: "colWidth", customCellTemplate: "customCellTemplate", valueCellTemplate: "valueCellTemplate", rowHeaderCellTemplate: "rowHeaderCellTemplate", columnHeaderCellTemplate: "columnHeaderCellTemplate", scrollableSettings: "scrollableSettings" }, ngImport: i0, template: `
3722
4014
  <table
3723
4015
  class="k-pivotgrid-table"
3724
- role="presentation">
4016
+ role="presentation"
4017
+ [ngStyle]="{float: this.tableType === 'values' ? this.rtl ? 'right' : 'left' : 'initial'}">
3725
4018
  <colgroup>
4019
+ <col *ngIf="tableType === 'values' && columnVirtualization && startColIndex > 0" [style.width]="startColIndex * (colWidth >= 0 ? colWidth : 200) + 'px'"/>
3726
4020
  <col
3727
- *ngFor="let item of headerItems;"
4021
+ *ngFor="let item of (tableType === 'values' && columnVirtualization ? headerItems?.slice(0, renderedCols) : headerItems);"
3728
4022
  [style.width]="tableType !== 'rowHeader' ? colWidth >= 0 ? colWidth + 'px' : '200px' : undefined" />
3729
4023
  </colgroup>
3730
4024
  <tbody class="k-pivotgrid-tbody" [attr.role]="tableType === 'values' ? 'none' : 'rowgroup'">
3731
- <tr *ngFor="let row of rows; index as rowIndex"
4025
+ <tr *ngFor="let row of (tableType === 'values' && rowVirtualization ? renderedRows : rows); index as rowIndex"
3732
4026
  class="k-pivotgrid-row"
3733
4027
  [attr.role]="tableType === 'values' ? 'none' : 'row'">
3734
- <ng-container *ngFor="let cell of row.cells; index as colIndex">
4028
+ <td *ngIf="tableType === 'values' && columnVirtualization && startColIndex > 0" class="k-pivotgrid-cell"></td>
4029
+ <ng-container *ngFor="let cell of (tableType === 'values' && columnVirtualization ? row.cells.slice(startColIndex, (startColIndex + renderedCols)) : row.cells); index as colIndex">
3735
4030
  <th
3736
4031
  *ngIf="cell && tableType !== 'values'"
3737
4032
  [kendoPivotGridCell]="cell"
@@ -3739,8 +4034,8 @@ PivotGridTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0"
3739
4034
  [rowHeaderCellTemplate]="rowHeaderCellTemplate"
3740
4035
  [columnHeaderCellTemplate]="columnHeaderCellTemplate"
3741
4036
  [tableType]="tableType"
3742
- [colIndex]="colIndex"
3743
- [rowIndex]="rowIndex"
4037
+ [colIndex]="colIndex + startColIndex"
4038
+ [rowIndex]="rowIndex + startRowIndex"
3744
4039
  [attr.aria-expanded]="cell.hasChildren && cell.children.length ? 'true' : 'false'"
3745
4040
  [attr.role]="tableType === 'columnHeader' ? 'columnheader' : tableType === 'rowHeader' ? 'rowheader' : 'none'"
3746
4041
  [attr.id]="pivotGridId + (tableType === 'columnHeader' ? 'ch-' : 'rh-') + (rowIndex + 1) + '-' + (colIndex + 1)"></th>
@@ -3750,15 +4045,15 @@ PivotGridTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0"
3750
4045
  [valueCellTemplate]="valueCellTemplate"
3751
4046
  [kendoPivotGridCell]="cell"
3752
4047
  tableType="values"
3753
- [colIndex]="colIndex"
3754
- [rowIndex]="rowIndex"
4048
+ [colIndex]="colIndex + startColIndex"
4049
+ [rowIndex]="rowIndex + startRowIndex"
3755
4050
  role="gridcell"
3756
- [attr.id]="pivotGridId + 'cell-' + (rowIndex + 1) + '-' + (colIndex + 1)"></td>
4051
+ [attr.id]="pivotGridId + 'cell-' + (rowIndex + startRowIndex + 1) + '-' + (colIndex + startColIndex + 1)"></td>
3757
4052
  </ng-container>
3758
4053
  </tr>
3759
4054
  </tbody>
3760
4055
  </table>
3761
- `, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PivotGridCellDirective, selector: "[kendoPivotGridCell]", inputs: ["kendoPivotGridCell", "tableType", "rowIndex", "colIndex", "customCellTemplate", "valueCellTemplate", "rowHeaderCellTemplate", "columnHeaderCellTemplate"] }] });
4056
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PivotGridCellDirective, selector: "[kendoPivotGridCell]", inputs: ["kendoPivotGridCell", "tableType", "rowIndex", "colIndex", "customCellTemplate", "valueCellTemplate", "rowHeaderCellTemplate", "columnHeaderCellTemplate"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
3762
4057
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridTableComponent, decorators: [{
3763
4058
  type: Component,
3764
4059
  args: [{
@@ -3766,17 +4061,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
3766
4061
  template: `
3767
4062
  <table
3768
4063
  class="k-pivotgrid-table"
3769
- role="presentation">
4064
+ role="presentation"
4065
+ [ngStyle]="{float: this.tableType === 'values' ? this.rtl ? 'right' : 'left' : 'initial'}">
3770
4066
  <colgroup>
4067
+ <col *ngIf="tableType === 'values' && columnVirtualization && startColIndex > 0" [style.width]="startColIndex * (colWidth >= 0 ? colWidth : 200) + 'px'"/>
3771
4068
  <col
3772
- *ngFor="let item of headerItems;"
4069
+ *ngFor="let item of (tableType === 'values' && columnVirtualization ? headerItems?.slice(0, renderedCols) : headerItems);"
3773
4070
  [style.width]="tableType !== 'rowHeader' ? colWidth >= 0 ? colWidth + 'px' : '200px' : undefined" />
3774
4071
  </colgroup>
3775
4072
  <tbody class="k-pivotgrid-tbody" [attr.role]="tableType === 'values' ? 'none' : 'rowgroup'">
3776
- <tr *ngFor="let row of rows; index as rowIndex"
4073
+ <tr *ngFor="let row of (tableType === 'values' && rowVirtualization ? renderedRows : rows); index as rowIndex"
3777
4074
  class="k-pivotgrid-row"
3778
4075
  [attr.role]="tableType === 'values' ? 'none' : 'row'">
3779
- <ng-container *ngFor="let cell of row.cells; index as colIndex">
4076
+ <td *ngIf="tableType === 'values' && columnVirtualization && startColIndex > 0" class="k-pivotgrid-cell"></td>
4077
+ <ng-container *ngFor="let cell of (tableType === 'values' && columnVirtualization ? row.cells.slice(startColIndex, (startColIndex + renderedCols)) : row.cells); index as colIndex">
3780
4078
  <th
3781
4079
  *ngIf="cell && tableType !== 'values'"
3782
4080
  [kendoPivotGridCell]="cell"
@@ -3784,8 +4082,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
3784
4082
  [rowHeaderCellTemplate]="rowHeaderCellTemplate"
3785
4083
  [columnHeaderCellTemplate]="columnHeaderCellTemplate"
3786
4084
  [tableType]="tableType"
3787
- [colIndex]="colIndex"
3788
- [rowIndex]="rowIndex"
4085
+ [colIndex]="colIndex + startColIndex"
4086
+ [rowIndex]="rowIndex + startRowIndex"
3789
4087
  [attr.aria-expanded]="cell.hasChildren && cell.children.length ? 'true' : 'false'"
3790
4088
  [attr.role]="tableType === 'columnHeader' ? 'columnheader' : tableType === 'rowHeader' ? 'rowheader' : 'none'"
3791
4089
  [attr.id]="pivotGridId + (tableType === 'columnHeader' ? 'ch-' : 'rh-') + (rowIndex + 1) + '-' + (colIndex + 1)"></th>
@@ -3795,19 +4093,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
3795
4093
  [valueCellTemplate]="valueCellTemplate"
3796
4094
  [kendoPivotGridCell]="cell"
3797
4095
  tableType="values"
3798
- [colIndex]="colIndex"
3799
- [rowIndex]="rowIndex"
4096
+ [colIndex]="colIndex + startColIndex"
4097
+ [rowIndex]="rowIndex + startRowIndex"
3800
4098
  role="gridcell"
3801
- [attr.id]="pivotGridId + 'cell-' + (rowIndex + 1) + '-' + (colIndex + 1)"></td>
4099
+ [attr.id]="pivotGridId + 'cell-' + (rowIndex + startRowIndex + 1) + '-' + (colIndex + startColIndex + 1)"></td>
3802
4100
  </ng-container>
3803
4101
  </tr>
3804
4102
  </tbody>
3805
4103
  </table>
3806
4104
  `,
3807
4105
  standalone: true,
3808
- imports: [NgFor, NgIf, PivotGridCellDirective]
4106
+ imports: [NgFor, NgIf, PivotGridCellDirective, NgStyle]
3809
4107
  }]
3810
- }], ctorParameters: function () { return [{ type: PivotGridDataService }]; }, propDecorators: { tableType: [{
4108
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: PivotGridDataService }, { type: i1$1.LocalizationService }, { type: PivotGridComponent }, { type: i0.NgZone }, { type: PivotGridScrollService }]; }, propDecorators: { tableType: [{
3811
4109
  type: Input
3812
4110
  }], colWidth: [{
3813
4111
  type: Input
@@ -3819,8 +4117,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
3819
4117
  type: Input
3820
4118
  }], columnHeaderCellTemplate: [{
3821
4119
  type: Input
4120
+ }], scrollableSettings: [{
4121
+ type: Input
3822
4122
  }] } });
3823
4123
 
4124
+ /**
4125
+ * @hidden
4126
+ */
4127
+ const DEFAULT_VIRTUALIZATION_SETTINGS = {
4128
+ type: 'both',
4129
+ rowHeight: 37,
4130
+ rows: 50,
4131
+ columns: 10
4132
+ };
4133
+ /**
4134
+ * @hidden
4135
+ */
4136
+ const normalizeVirtualSettings = (settings) => {
4137
+ if (settings === true) {
4138
+ return { ...DEFAULT_VIRTUALIZATION_SETTINGS };
4139
+ }
4140
+ if (!settings) {
4141
+ return null;
4142
+ }
4143
+ return { ...DEFAULT_VIRTUALIZATION_SETTINGS, ...settings };
4144
+ };
4145
+
3824
4146
  const DEFAULT_LOADER_SETTINGS = {
3825
4147
  type: 'converging-spinner',
3826
4148
  themeColor: 'primary',
@@ -3834,12 +4156,13 @@ const DEFAULT_CONFIGURATOR_SETTINGS = {
3834
4156
  * Represents the Kendo UI PivotGrid component for Angular.
3835
4157
  */
3836
4158
  class PivotGridComponent {
3837
- constructor(hostEl, zone, dataService, localization, renderer, _scrollbarWidthService) {
4159
+ constructor(hostEl, zone, dataService, localization, renderer, _scrollbarWidthService, scrollService) {
3838
4160
  this.hostEl = hostEl;
3839
4161
  this.zone = zone;
3840
4162
  this.dataService = dataService;
3841
4163
  this.localization = localization;
3842
4164
  this.renderer = renderer;
4165
+ this.scrollService = scrollService;
3843
4166
  this.hostClass = true;
3844
4167
  /**
3845
4168
  * Specify the width of the column header and data cells. Value is treated as pixels [(see example)]({% slug appearance_pivotgrid %}#toc-column-headers-width).
@@ -3859,6 +4182,7 @@ class PivotGridComponent {
3859
4182
  this.gearSVGIcon = gearIcon;
3860
4183
  this.resizeObservers = [];
3861
4184
  this._loaderSettings = DEFAULT_LOADER_SETTINGS;
4185
+ this._virtualScrolling = normalizeVirtualSettings(false);
3862
4186
  this.subs = new Subscription();
3863
4187
  this.rtl = false;
3864
4188
  this.resizeContainer = (axis, element) => {
@@ -3924,6 +4248,18 @@ class PivotGridComponent {
3924
4248
  get loadingText() {
3925
4249
  return this.localization.get('loading');
3926
4250
  }
4251
+ /**
4252
+ * Sets the virtualization options of the component. By default the virtual scrolling functionality is disabled.
4253
+ *
4254
+ * @default false
4255
+ */
4256
+ set virtualScrolling(value) {
4257
+ this._virtualScrolling = normalizeVirtualSettings(value);
4258
+ this.scrollService.virtualScrolling = !!value;
4259
+ }
4260
+ get virtualScrolling() {
4261
+ return this._virtualScrolling;
4262
+ }
3927
4263
  get configuratorSettings() {
3928
4264
  return this.configurator && Object.assign({}, DEFAULT_CONFIGURATOR_SETTINGS, this.configurator);
3929
4265
  }
@@ -3998,6 +4334,9 @@ class PivotGridComponent {
3998
4334
  }
3999
4335
  }
4000
4336
  }
4337
+ /**
4338
+ * @hidden
4339
+ */
4001
4340
  initNavigation() {
4002
4341
  this.stopNavigation();
4003
4342
  this.navigation = new PivotGridNavigation({ tabIndex: 0 });
@@ -4038,15 +4377,16 @@ class PivotGridComponent {
4038
4377
  }
4039
4378
  }
4040
4379
  }
4041
- PivotGridComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridComponent, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { token: PivotGridDataService }, { token: i1$1.LocalizationService }, { token: i0.Renderer2 }, { token: i1$4.ScrollbarWidthService }], target: i0.ɵɵFactoryTarget.Component });
4042
- PivotGridComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: PivotGridComponent, isStandalone: true, selector: "kendo-pivotgrid", inputs: { loaderSettings: "loaderSettings", configurator: "configurator", columnHeadersWidth: "columnHeadersWidth", navigable: "navigable" }, host: { properties: { "class.k-d-flex": "this.hostClass", "class.k-pos-relative": "this.hostClass", "class.k-flex-row": "this.rightPositionClass", "class.k-flex-row-reverse": "this.leftPositionClass", "class.k-flex-column": "this.bottomPositionClass", "class.k-flex-column-reverse": "this.topPositionClass", "attr.dir": "this.dir" } }, providers: [
4380
+ PivotGridComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridComponent, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { token: PivotGridDataService }, { token: i1$1.LocalizationService }, { token: i0.Renderer2 }, { token: i1$4.ScrollbarWidthService }, { token: PivotGridScrollService }], target: i0.ɵɵFactoryTarget.Component });
4381
+ PivotGridComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: PivotGridComponent, isStandalone: true, selector: "kendo-pivotgrid", inputs: { loaderSettings: "loaderSettings", configurator: "configurator", virtualScrolling: "virtualScrolling", columnHeadersWidth: "columnHeadersWidth", navigable: "navigable" }, host: { properties: { "class.k-d-flex": "this.hostClass", "class.k-pos-relative": "this.hostClass", "class.k-flex-row": "this.rightPositionClass", "class.k-flex-row-reverse": "this.leftPositionClass", "class.k-flex-column": "this.bottomPositionClass", "class.k-flex-column-reverse": "this.topPositionClass", "attr.dir": "this.dir" } }, providers: [
4043
4382
  PivotGridDataService,
4044
4383
  LocalizationService,
4045
4384
  PivotLocalizationService,
4046
4385
  {
4047
4386
  provide: L10N_PREFIX,
4048
4387
  useValue: 'kendo.pivotgrid'
4049
- }
4388
+ },
4389
+ PivotGridScrollService
4050
4390
  ], queries: [{ propertyName: "customCellTemplate", first: true, predicate: CellTemplateDirective, descendants: true }, { propertyName: "valueCellTemplate", first: true, predicate: ValueCellTemplateDirective, descendants: true }, { propertyName: "rowHeaderCellTemplate", first: true, predicate: RowHeaderCellTemplateDirective, descendants: true }, { propertyName: "columnHeaderCellTemplate", first: true, predicate: ColumnHeaderCellTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "colHeadersTable", first: true, predicate: ["colHeadersTable"], descendants: true, read: ElementRef }, { propertyName: "rowHeadersTable", first: true, predicate: ["rowHeadersTable"], descendants: true, read: ElementRef }, { propertyName: "valuesTable", first: true, predicate: ["valuesTable"], descendants: true, read: ElementRef }, { propertyName: "table", first: true, predicate: ["table"], descendants: true, read: ElementRef }, { propertyName: "configuratorWrapper", first: true, predicate: ["configurator"], descendants: true, read: ElementRef }], usesOnChanges: true, ngImport: i0, template: `
4051
4391
  <ng-container kendoPivotGridLocalizedMessages
4052
4392
  i18n-loading="kendo.pivotgrid.loading|The loading text"
@@ -4177,6 +4517,7 @@ PivotGridComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", ver
4177
4517
  [valueCellTemplate]="valueCellTemplate"
4178
4518
  [colWidth]="columnHeadersWidth"
4179
4519
  class="k-pivotgrid-values"
4520
+ [scrollableSettings]="virtualScrolling"
4180
4521
  tableType="values"></kendo-pivotgrid-table>
4181
4522
 
4182
4523
  <div *ngIf="loading" [style]="'position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);'">
@@ -4204,7 +4545,7 @@ PivotGridComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", ver
4204
4545
  <span>{{messageFor('configuratorButtonText')}}<kendo-icon-wrapper name="gear" innerCssClass="k-color-inherit" [svgIcon]="gearSVGIcon"></kendo-icon-wrapper>
4205
4546
  </span>
4206
4547
  </div>
4207
- `, isInline: true, dependencies: [{ kind: "directive", type: LocalizedMessagesDirective, selector: "[kendoPivotGridLocalizedMessages]" }, { kind: "component", type: PivotGridTableComponent, selector: "kendo-pivotgrid-table", inputs: ["tableType", "colWidth", "customCellTemplate", "valueCellTemplate", "rowHeaderCellTemplate", "columnHeaderCellTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: LoaderComponent, selector: "kendo-loader", inputs: ["type", "themeColor", "size"] }, { kind: "component", type: PivotGridConfiguratorComponent, selector: "kendo-pivotgrid-configurator", inputs: ["orientation", "sort", "filter", "navigation"], outputs: ["close"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }] });
4548
+ `, isInline: true, dependencies: [{ kind: "directive", type: LocalizedMessagesDirective, selector: "[kendoPivotGridLocalizedMessages]" }, { kind: "component", type: PivotGridTableComponent, selector: "kendo-pivotgrid-table", inputs: ["tableType", "colWidth", "customCellTemplate", "valueCellTemplate", "rowHeaderCellTemplate", "columnHeaderCellTemplate", "scrollableSettings"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: LoaderComponent, selector: "kendo-loader", inputs: ["type", "themeColor", "size"] }, { kind: "component", type: PivotGridConfiguratorComponent, selector: "kendo-pivotgrid-configurator", inputs: ["orientation", "sort", "filter", "navigation"], outputs: ["close"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }] });
4208
4549
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: PivotGridComponent, decorators: [{
4209
4550
  type: Component,
4210
4551
  args: [{
@@ -4216,7 +4557,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
4216
4557
  {
4217
4558
  provide: L10N_PREFIX,
4218
4559
  useValue: 'kendo.pivotgrid'
4219
- }
4560
+ },
4561
+ PivotGridScrollService
4220
4562
  ],
4221
4563
  template: `
4222
4564
  <ng-container kendoPivotGridLocalizedMessages
@@ -4348,6 +4690,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
4348
4690
  [valueCellTemplate]="valueCellTemplate"
4349
4691
  [colWidth]="columnHeadersWidth"
4350
4692
  class="k-pivotgrid-values"
4693
+ [scrollableSettings]="virtualScrolling"
4351
4694
  tableType="values"></kendo-pivotgrid-table>
4352
4695
 
4353
4696
  <div *ngIf="loading" [style]="'position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);'">
@@ -4379,7 +4722,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
4379
4722
  standalone: true,
4380
4723
  imports: [LocalizedMessagesDirective, PivotGridTableComponent, NgIf, LoaderComponent, PivotGridConfiguratorComponent, IconWrapperComponent]
4381
4724
  }]
4382
- }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: PivotGridDataService }, { type: i1$1.LocalizationService }, { type: i0.Renderer2 }, { type: i1$4.ScrollbarWidthService }]; }, propDecorators: { hostClass: [{
4725
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.NgZone }, { type: PivotGridDataService }, { type: i1$1.LocalizationService }, { type: i0.Renderer2 }, { type: i1$4.ScrollbarWidthService }, { type: PivotGridScrollService }]; }, propDecorators: { hostClass: [{
4383
4726
  type: HostBinding,
4384
4727
  args: ['class.k-d-flex']
4385
4728
  }, {
@@ -4431,6 +4774,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImpo
4431
4774
  type: Input
4432
4775
  }], configurator: [{
4433
4776
  type: Input
4777
+ }], virtualScrolling: [{
4778
+ type: Input
4434
4779
  }], columnHeadersWidth: [{
4435
4780
  type: Input
4436
4781
  }], navigable: [{