@@ -195,8 +195,6 @@ export class MenuItem extends LikeAnchor(
195195
196196    private  _value  =  '' ; 
197197
198-     private  _lastPointerType ?: string ; 
199- 
200198    /** 
201199     * @private  
202200     * text content of the menu item minus whitespace 
@@ -459,15 +457,25 @@ export class MenuItem extends LikeAnchor(
459457        } 
460458    } 
461459
460+     private  handlePointerdown ( event : PointerEvent ) : void { 
461+         if  ( event . target  ===  this  &&  this . hasSubmenu  &&  this . open )  { 
462+             this . addEventListener ( 'focus' ,  this . handleSubmenuFocus ,  { 
463+                 once : true , 
464+             } ) ; 
465+             this . overlayElement . addEventListener ( 
466+                 'beforetoggle' , 
467+                 this . handleBeforetoggle 
468+             ) ; 
469+         } 
470+     } 
471+ 
462472    protected  override  firstUpdated ( changes : PropertyValues ) : void { 
463473        super . firstUpdated ( changes ) ; 
464474        this . setAttribute ( 'tabindex' ,  '-1' ) ; 
465475        this . addEventListener ( 'keydown' ,  this . handleKeydown ) ; 
466476        this . addEventListener ( 'mouseover' ,  this . handleMouseover ) ; 
467-         // Register pointerenter/leave for ALL menu items (not just those with submenus) 
468-         // so items without submenus can close sibling submenus when hovered 
469-         this . addEventListener ( 'pointerenter' ,  this . handlePointerenter ) ; 
470-         this . addEventListener ( 'pointerleave' ,  this . handlePointerleave ) ; 
477+         this . addEventListener ( 'pointerdown' ,  this . handlePointerdown ) ; 
478+         this . addEventListener ( 'pointerenter' ,  this . closeOverlaysForRoot ) ; 
471479        if  ( ! this . hasAttribute ( 'id' ) )  { 
472480            this . id  =  `sp-menu-item-${ randomID ( ) }  ; 
473481        } 
@@ -586,6 +594,11 @@ export class MenuItem extends LikeAnchor(
586594        } 
587595    } ; 
588596
597+     protected  closeOverlaysForRoot ( ) : void { 
598+         if  ( this . open )  return ; 
599+         this . menuData . parentMenu ?. closeDescendentOverlays ( ) ; 
600+     } 
601+ 
589602    protected  handleFocus ( event : FocusEvent ) : void { 
590603        const  {  target }  =  event ; 
591604        if  ( target  ===  this )  { 
@@ -600,64 +613,48 @@ export class MenuItem extends LikeAnchor(
600613        } 
601614    } 
602615
603-     protected  handleSubmenuTriggerClick ( event : Event ) : void { 
616+     protected  handleSubmenuClick ( event : Event ) : void { 
604617        if  ( event . composedPath ( ) . includes ( this . overlayElement ) )  { 
605618            return ; 
606619        } 
607- 
608-         // If submenu is already open, toggle it closed 
609-         if  ( this . open  &&  this . _lastPointerType  ===  'touch' )  { 
610-             event . preventDefault ( ) ; 
611-             event . stopPropagation ( ) ;  // Don't let parent menu handle this 
612-             this . open  =  false ; 
613-             return ; 
614-         } 
615- 
616-         // All: open if closed 
617-         if  ( ! this . open )  { 
618-             event . preventDefault ( ) ; 
619-             event . stopImmediatePropagation ( ) ; 
620-             this . openOverlay ( true ) ; 
621-         } 
620+         this . openOverlay ( true ) ; 
622621    } 
623622
624-     protected  handlePointerenter ( event : PointerEvent ) : void { 
625-         this . _lastPointerType  =  event . pointerType ;  // Track pointer type 
623+     protected  handleSubmenuFocus ( ) : void { 
624+         requestAnimationFrame ( ( )  =>  { 
625+             // Wait till after `closeDescendentOverlays` has happened in Menu 
626+             // to reopen (keep open) the direct descendent of this Menu Item 
627+             this . overlayElement . open  =  this . open ; 
628+             this . focused  =  false ; 
629+         } ) ; 
630+     } 
626631
627-         // For touch: don't handle pointerenter, let click handle it 
628-         if  ( event . pointerType  ===  'touch' )  { 
629-             return ; 
632+     protected  handleBeforetoggle  =  ( event : Event ) : void =>  { 
633+         if  ( ( event  as  Event  &  {  newState : string  } ) . newState  ===  'closed' )  { 
634+             this . open  =  true ; 
635+             this . overlayElement . manuallyKeepOpen ( ) ; 
636+             this . overlayElement . removeEventListener ( 
637+                 'beforetoggle' , 
638+                 this . handleBeforetoggle 
639+             ) ; 
630640        } 
641+     } ; 
631642
632-         // Close sibling submenus before opening this one 
633-         this . menuData . parentMenu ?. closeDescendentOverlays ( ) ; 
634- 
643+     protected  handlePointerenter ( ) : void { 
635644        if  ( this . leaveTimeout )  { 
636645            clearTimeout ( this . leaveTimeout ) ; 
637646            delete  this . leaveTimeout ; 
638647            this . recentlyLeftChild  =  false ; 
639648            return ; 
640649        } 
641- 
642-         // Only focus items with submenus on hover (to show they're interactive) 
643-         // Regular items should not show focus styling on hover, only on keyboard navigation 
644-         if  ( this . hasSubmenu )  { 
645-             this . focus ( ) ; 
646-         } 
650+         this . focus ( ) ; 
647651        this . openOverlay ( ) ; 
648652    } 
649653
650654    protected  leaveTimeout ?: ReturnType < typeof  setTimeout > ; 
651655    protected  recentlyLeftChild  =  false ; 
652656
653-     protected  handlePointerleave ( event : PointerEvent ) : void { 
654-         this . _lastPointerType  =  event . pointerType ;  // Update on leave too 
655- 
656-         // For touch: don't handle pointerleave, let click handle it 
657-         if  ( event . pointerType  ===  'touch' )  { 
658-             return ; 
659-         } 
660- 
657+     protected  handlePointerleave ( ) : void { 
661658        this . _closedViaPointer  =  true ; 
662659        if  ( this . open  &&  ! this . recentlyLeftChild )  { 
663660            this . leaveTimeout  =  setTimeout ( ( )  =>  { 
@@ -785,7 +782,17 @@ export class MenuItem extends LikeAnchor(
785782                const  options  =  {  signal : this . abortControllerSubmenu . signal  } ; 
786783                this . addEventListener ( 
787784                    'click' , 
788-                     this . handleSubmenuTriggerClick , 
785+                     this . handleSubmenuClick , 
786+                     options 
787+                 ) ; 
788+                 this . addEventListener ( 
789+                     'pointerenter' , 
790+                     this . handlePointerenter , 
791+                     options 
792+                 ) ; 
793+                 this . addEventListener ( 
794+                     'pointerleave' , 
795+                     this . handlePointerleave , 
789796                    options 
790797                ) ; 
791798                this . addEventListener ( 
0 commit comments