Skip to content

Commit 8fd197c

Browse files
chore(overlay): optimize backdrop click detection and event handling (#5967)
1 parent 2732aad commit 8fd197c

File tree

5 files changed

+34
-29
lines changed

5 files changed

+34
-29
lines changed

1st-gen/packages/action-button/src/ActionButton.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,6 @@ export class ActionButton extends SizedMixin(ButtonBase, {
179179
if (code === 'Space' || (altKey && code === 'ArrowDown')) {
180180
event.preventDefault();
181181
if (code === 'ArrowDown') {
182-
event.stopPropagation();
183182
event.stopImmediatePropagation();
184183
}
185184
this.addEventListener('keyup', this.handleKeyup);

1st-gen/packages/button/src/ButtonBase.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ export class ButtonBase extends ObserveSlotText(LikeAnchor(Focusable), '', [
8989
if (this.disabled) {
9090
event.preventDefault();
9191
event.stopImmediatePropagation();
92-
event.stopPropagation();
9392
return false;
9493
}
9594

1st-gen/packages/menu/src/MenuItem.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,6 @@ export class MenuItem extends LikeAnchor(
331331
if (this.disabled) {
332332
event.preventDefault();
333333
event.stopImmediatePropagation();
334-
event.stopPropagation();
335334
return false;
336335
}
337336

1st-gen/packages/overlay/src/LongpressController.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ export class LongpressController extends InteractionController {
9595
private handleKeydown(event: KeyboardEvent): void {
9696
const { code, altKey } = event;
9797
if (altKey && code === 'ArrowDown') {
98-
event.stopPropagation();
9998
event.stopImmediatePropagation();
10099
}
101100
}

1st-gen/packages/overlay/src/OverlayStack.ts

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -163,23 +163,22 @@ class OverlayStack {
163163
* @param event {PointerEvent}
164164
*/
165165
handlePointerdown = (event: Event): void => {
166+
if (!this.stack.length) return;
167+
166168
const pointerPath = event.composedPath();
167169

168170
// For page overlays only: block clicks outside (no light dismiss)
169171
// Modal overlays have light dismiss handled by handlePointerup
170-
if (this.stack.length) {
171-
const pageOverlays = this.stack.filter(
172-
(o) => o.open && o.type === 'page'
173-
);
174-
if (
175-
pageOverlays.length > 0 &&
176-
!this.isEventInsideModal(pointerPath, pageOverlays)
177-
) {
178-
event.preventDefault();
179-
event.stopPropagation();
180-
event.stopImmediatePropagation();
181-
return;
182-
}
172+
const pageOverlays = this.stack.filter(
173+
(o) => o.open && o.type === 'page'
174+
);
175+
if (
176+
pageOverlays.length > 0 &&
177+
!this.isEventInsideModal(pointerPath, pageOverlays)
178+
) {
179+
event.preventDefault();
180+
event.stopImmediatePropagation();
181+
return;
183182
}
184183

185184
this.pointerdownPath = pointerPath;
@@ -210,7 +209,6 @@ class OverlayStack {
210209
// If click is outside all page overlays, prevent it from reaching the target
211210
// This replicates the behavior that showModal() provided automatically
212211
event.stopImmediatePropagation();
213-
event.stopPropagation();
214212
event.preventDefault();
215213
}
216214
};
@@ -232,19 +230,30 @@ class OverlayStack {
232230
this.lastOverlay = undefined;
233231

234232
const lastIndex = this.stack.length - 1;
235-
const clickedBackdrop = composedPath.some(
236-
(el) =>
237-
el instanceof HTMLElement &&
238-
el.classList.contains('modal-backdrop')
233+
234+
// Avoid the cost of event.composedPath() unless we actually have a modal/page
235+
// overlay open. composedPath() walks and allocates the full event path and can
236+
// be surprisingly expensive in hot paths.
237+
const hasModalOrPageOverlay = this.stack.some(
238+
(overlay) =>
239+
overlay.open &&
240+
(overlay.type === 'modal' || overlay.type === 'page')
239241
);
240-
if (clickedBackdrop) {
241-
const topOverlay = this.stack[this.stack.length - 1];
242-
// Only modal overlays close on backdrop click.
243-
// Page overlays are blocking and should not be light-dismissable.
244-
if (topOverlay?.type === 'modal') {
245-
this.closeOverlay(topOverlay);
242+
if (hasModalOrPageOverlay) {
243+
const clickedBackdrop = composedPath.some(
244+
(el) =>
245+
el instanceof HTMLDivElement &&
246+
el.classList.contains('modal-backdrop')
247+
);
248+
if (clickedBackdrop) {
249+
const topOverlay = this.stack[this.stack.length - 1];
250+
// Only modal overlays close on backdrop click.
251+
// Page overlays are blocking and should not be light-dismissable.
252+
if (topOverlay?.type === 'modal') {
253+
this.closeOverlay(topOverlay);
254+
}
255+
return;
246256
}
247-
return;
248257
}
249258
const nonAncestorOverlays = this.stack.filter((overlay, i) => {
250259
const inStack = composedPath.find(

0 commit comments

Comments
 (0)