Skip to content

Commit 3d46cc3

Browse files
author
Helen Le
committed
fix(menu): patch scroll fix
1 parent 1cadc7b commit 3d46cc3

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

packages/menu/src/Menu.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,22 @@ export class Menu extends SizedMixin(SpectrumElement, { noDefaultSize: true }) {
7272

7373
protected rovingTabindexController?: RovingTabindexController<MenuItem>;
7474

75+
private touchStartY: number | undefined = undefined;
76+
private touchStartTime: number | undefined = undefined;
77+
private isCurrentlyScrolling = false;
78+
79+
private scrollThreshold = 10; // pixels
80+
private scrollTimeThreshold = 300; // milliseconds
81+
82+
public get isScrolling(): boolean {
83+
return this.isCurrentlyScrolling;
84+
}
85+
86+
public set isScrolling(value: boolean) {
87+
// For testing purposes, allow setting the scrolling state
88+
this.isCurrentlyScrolling = value;
89+
}
90+
7591
/**
7692
* label of the menu
7793
*/
@@ -400,6 +416,13 @@ export class Menu extends SizedMixin(SpectrumElement, { noDefaultSize: true }) {
400416
this.addEventListener('pointerup', this.handlePointerup);
401417
this.addEventListener('sp-opened', this.handleSubmenuOpened);
402418
this.addEventListener('sp-closed', this.handleSubmenuClosed);
419+
420+
this.addEventListener('touchstart', this.handleTouchStart, {
421+
passive: true,
422+
});
423+
this.addEventListener('touchmove', this.handleTouchMove, {
424+
passive: true,
425+
});
403426
}
404427

405428
/**
@@ -443,6 +466,42 @@ export class Menu extends SizedMixin(SpectrumElement, { noDefaultSize: true }) {
443466
}
444467
}
445468

469+
private handleTouchStart(event: TouchEvent): void {
470+
if (event.touches.length === 1) {
471+
this.touchStartY = event.touches[0].clientY;
472+
this.touchStartTime = Date.now();
473+
this.isCurrentlyScrolling = false;
474+
}
475+
}
476+
477+
private handleTouchMove(event: TouchEvent): void {
478+
if (
479+
event.touches.length === 1 &&
480+
this.touchStartY !== undefined &&
481+
this.touchStartTime !== undefined
482+
) {
483+
const currentY = event.touches[0].clientY;
484+
const deltaY = Math.abs(currentY - this.touchStartY);
485+
const deltaTime = Date.now() - this.touchStartTime;
486+
487+
if (
488+
deltaY > this.scrollThreshold &&
489+
deltaTime < this.scrollTimeThreshold
490+
) {
491+
this.isCurrentlyScrolling = true;
492+
}
493+
}
494+
}
495+
496+
private handleTouchEnd(): void {
497+
// Reset scrolling state after a short delay
498+
setTimeout(() => {
499+
this.isCurrentlyScrolling = false;
500+
this.touchStartY = undefined;
501+
this.touchStartTime = undefined;
502+
}, 100);
503+
}
504+
446505
// if the click and pointerup events are on the same target, we should not
447506
// handle the click event.
448507
private pointerUpTarget = null as EventTarget | null;
@@ -461,6 +520,7 @@ export class Menu extends SizedMixin(SpectrumElement, { noDefaultSize: true }) {
461520
}
462521

463522
private handlePointerup(event: Event): void {
523+
this.handleTouchEnd();
464524
/*
465525
* early return if drag and select is not supported
466526
* in this case, selection will be handled by the click event
@@ -478,6 +538,10 @@ export class Menu extends SizedMixin(SpectrumElement, { noDefaultSize: true }) {
478538
return;
479539
}
480540

541+
if (this.isScrolling) {
542+
return;
543+
}
544+
481545
const path = event.composedPath();
482546
const target = path.find((el) => {
483547
/* c8 ignore next 3 */

0 commit comments

Comments
 (0)