Skip to content

Commit

Permalink
fix(Menu): handle pseudo-element bounds in trigger click detection
Browse files Browse the repository at this point in the history
- Add getPseudoElementPadding utility to compute ::before/::after dimensions
- Refactor mouseup handler to check extended clickable area
- Update click detection logic to include pseudo-element padding
- Improve trigger bounds calculation for more accurate click handling

Fixes mui#1232 - Prevents menu from closing unexpectedly when clicking within
the pseudo-element extended area of the trigger.
  • Loading branch information
onehanddev committed Dec 31, 2024
1 parent d9ef5c6 commit 4c17eea
Showing 1 changed file with 32 additions and 9 deletions.
41 changes: 32 additions & 9 deletions packages/react/src/menu/trigger/useMenuTrigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,25 @@ export function useMenuTrigger(parameters: useMenuTrigger.Parameters): useMenuTr

const doc = ownerDocument(event.currentTarget);

function getPseudoElementPadding(triggerRefElement: HTMLElement) {
const beforeStyles = window.getComputedStyle(triggerRefElement, '::before');
const afterStyles = window.getComputedStyle(triggerRefElement, '::after');

const hasPseudoElements =
beforeStyles.content !== 'none' || afterStyles.content !== 'none';

const padding = hasPseudoElements
? Math.max(
parseInt(beforeStyles.width || '0', 10),
parseInt(afterStyles.width || '0', 10),
parseInt(beforeStyles.height || '0', 10),
parseInt(afterStyles.height || '0', 10),
) / 2
: 0;

return padding;
}

function handleMouseUp(mouseEvent: MouseEvent) {
if (!triggerRef.current) {
return;
Expand All @@ -71,18 +90,22 @@ export function useMenuTrigger(parameters: useMenuTrigger.Parameters): useMenuTr

const mouseUpTarget = mouseEvent.target as Element | null;

const triggerRect = triggerRef.current.getBoundingClientRect();
if (
contains(triggerRef.current, mouseUpTarget) ||
contains(positionerRef.current, mouseUpTarget) ||
mouseUpTarget === triggerRef.current
) {
return;
}

const isInsideTrigger =
mouseEvent.clientX >= triggerRect.left &&
mouseEvent.clientX <= triggerRect.right &&
mouseEvent.clientY >= triggerRect.top &&
mouseEvent.clientY <= triggerRect.bottom;
const padding = getPseudoElementPadding(triggerRef.current);
const triggerRect = triggerRef.current.getBoundingClientRect();

if (
isInsideTrigger ||
contains(positionerRef.current, mouseUpTarget) ||
contains(triggerRef.current, mouseUpTarget)
mouseEvent.clientX >= triggerRect.left - padding &&
mouseEvent.clientX <= triggerRect.right + padding &&
mouseEvent.clientY >= triggerRect.top - padding &&
mouseEvent.clientY <= triggerRect.bottom + padding
) {
return;
}
Expand Down

0 comments on commit 4c17eea

Please sign in to comment.