From 69991b09ccaaae0f9db6b8426ff2ce30dae3d9f4 Mon Sep 17 00:00:00 2001 From: Daniel Olaru Date: Tue, 25 Mar 2025 17:01:16 +0200 Subject: [PATCH] perf(cdk-experimental/column-resize): add debounce to column header hover to prevent excessive handler rendering Improve the user experience and performance of the `cdk-experimental` column resize feature by adding a `debounceTime` operator to the `headerCellHoveredDistinct` observable. Previously, the hover event triggered the handler immediately, which could result in unwanted handlers showing up when the user quickly moved their cursor over column headers. This change ensures that the handlers only appear if the user pauses (hovers for 300ms) over the column header, preventing handlers from rendering during fast cursor movements. --- .../column-resize/event-dispatcher.ts | 8 ++++++-- .../column-resize/column-resize.spec.ts | 12 +++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/cdk-experimental/column-resize/event-dispatcher.ts b/src/cdk-experimental/column-resize/event-dispatcher.ts index f7c8e19adf3d..52c16ed8f69d 100644 --- a/src/cdk-experimental/column-resize/event-dispatcher.ts +++ b/src/cdk-experimental/column-resize/event-dispatcher.ts @@ -8,7 +8,7 @@ import {Injectable, NgZone, inject} from '@angular/core'; import {combineLatest, MonoTypeOperatorFunction, Observable, Subject} from 'rxjs'; -import {distinctUntilChanged, map, share, skip, startWith} from 'rxjs/operators'; +import {distinctUntilChanged, map, share, skip, startWith, debounceTime} from 'rxjs/operators'; import {_closest} from '../popover-edit'; @@ -33,7 +33,11 @@ export class HeaderRowEventDispatcher { readonly overlayHandleActiveForCell = new Subject(); /** Distinct and shared version of headerCellHovered. */ - readonly headerCellHoveredDistinct = this.headerCellHovered.pipe(distinctUntilChanged(), share()); + readonly headerCellHoveredDistinct = this.headerCellHovered.pipe( + distinctUntilChanged(), + debounceTime(200), + share(), + ); /** * Emits the header that is currently hovered or hosting an active resize event (with active diff --git a/src/material-experimental/column-resize/column-resize.spec.ts b/src/material-experimental/column-resize/column-resize.spec.ts index 045ad22c6d82..4acb3f27046c 100644 --- a/src/material-experimental/column-resize/column-resize.spec.ts +++ b/src/material-experimental/column-resize/column-resize.spec.ts @@ -9,7 +9,7 @@ import { Injectable, ViewChild, } from '@angular/core'; -import {ComponentFixture, TestBed, fakeAsync, flush} from '@angular/core/testing'; +import {ComponentFixture, TestBed, fakeAsync, flush, tick} from '@angular/core/testing'; import {MatTableModule} from '@angular/material/table'; import {BehaviorSubject, Observable, ReplaySubject} from 'rxjs'; import {dispatchKeyboardEvent} from '../../cdk/testing/private'; @@ -401,6 +401,7 @@ describe('Material Popover Edit', () => { component.triggerHoverState(); fixture.detectChanges(); + tick(200); expect( component.getOverlayThumbElement(0).classList.contains('mat-column-resize-overlay-thumb'), @@ -438,6 +439,7 @@ describe('Material Popover Edit', () => { component.completeResizeWithMouseInProgress(0); component.endHoverState(); fixture.detectChanges(); + tick(200); flush(); expect(component.getOverlayThumbElement(0)).toBeUndefined(); @@ -451,6 +453,7 @@ describe('Material Popover Edit', () => { component.triggerHoverState(); fixture.detectChanges(); + tick(200); component.beginColumnResizeWithMouse(1); const initialThumbPosition = component.getOverlayThumbPosition(1); @@ -500,6 +503,7 @@ describe('Material Popover Edit', () => { component.triggerHoverState(); fixture.detectChanges(); + tick(200); component.beginColumnResizeWithMouse(1); const initialThumbPosition = component.getOverlayThumbPosition(1); @@ -535,6 +539,7 @@ describe('Material Popover Edit', () => { component.triggerHoverState(); fixture.detectChanges(); + tick(200); component.beginColumnResizeWithMouse(1, 2); const initialPosition = component.getOverlayThumbPosition(1); @@ -552,6 +557,7 @@ describe('Material Popover Edit', () => { component.triggerHoverState(); fixture.detectChanges(); + tick(200); component.beginColumnResizeWithMouse(1); const initialThumbPosition = component.getOverlayThumbPosition(1); @@ -589,6 +595,7 @@ describe('Material Popover Edit', () => { component.triggerHoverState(); fixture.detectChanges(); + tick(200); expect(resize).toBe(null); @@ -610,6 +617,7 @@ describe('Material Popover Edit', () => { component.triggerHoverState(); fixture.detectChanges(); + tick(200); component.beginColumnResizeWithMouse(0); component.updateResizeWithMouseInProgress(5); @@ -674,6 +682,7 @@ describe('Material Popover Edit', () => { component.triggerHoverState(); fixture.detectChanges(); + tick(200); component.resizeColumnWithMouse(1, 5); fixture.detectChanges(); @@ -699,6 +708,7 @@ describe('Material Popover Edit', () => { component.triggerHoverState(); fixture.detectChanges(); + tick(200); component.resizeColumnWithMouse(1, 5); fixture.detectChanges();