@@ -9,6 +9,7 @@ import useId from 'rc-util/lib/hooks/useId';
99import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect' ;
1010import isMobile from 'rc-util/lib/isMobile' ;
1111import * as React from 'react' ;
12+ import { flushSync } from 'react-dom' ;
1213import type { TriggerContextProps } from './context' ;
1314import TriggerContext from './context' ;
1415import useAction from './hooks/useAction' ;
@@ -307,10 +308,14 @@ export function generateTrigger(
307308 openRef . current = mergedOpen ;
308309
309310 const internalTriggerOpen = useEvent ( ( nextOpen : boolean ) => {
310- if ( mergedOpen !== nextOpen ) {
311- setMergedOpen ( nextOpen ) ;
312- onPopupVisibleChange ?.( nextOpen ) ;
313- }
311+ // Enter or Pointer will both trigger open state change
312+ // We only need take one to avoid duplicated change event trigger
313+ flushSync ( ( ) => {
314+ if ( mergedOpen !== nextOpen ) {
315+ setMergedOpen ( nextOpen ) ;
316+ onPopupVisibleChange ?.( nextOpen ) ;
317+ }
318+ } ) ;
314319 } ) ;
315320
316321 // Trigger for delay
@@ -354,7 +359,9 @@ export function generateTrigger(
354359 0 , 0 ,
355360 ] ) ;
356361
357- const setMousePosByEvent = ( event : React . MouseEvent ) => {
362+ const setMousePosByEvent = (
363+ event : Pick < React . MouseEvent , 'clientX' | 'clientY' > ,
364+ ) => {
358365 setMousePos ( [ event . clientX , event . clientY ] ) ;
359366 } ;
360367
@@ -463,21 +470,23 @@ export function generateTrigger(
463470 hideAction ,
464471 ) ;
465472
466- // Util wrapper for trigger action
467- const wrapperAction = (
473+ /**
474+ * Util wrapper for trigger action
475+ */
476+ function wrapperAction < Event extends React . SyntheticEvent > (
468477 eventName : string ,
469478 nextOpen : boolean ,
470479 delay ?: number ,
471- preEvent ?: ( event : any ) => void ,
472- ) => {
480+ preEvent ?: ( event : Event ) => void ,
481+ ) {
473482 cloneProps [ eventName ] = ( event : any , ...args : any [ ] ) => {
474483 preEvent ?.( event ) ;
475484 triggerOpen ( nextOpen , delay ) ;
476485
477486 // Pass to origin
478487 originChildProps [ eventName ] ?.( event , ...args ) ;
479488 } ;
480- } ;
489+ }
481490
482491 // ======================= Action: Click ========================
483492 const clickToShow = showActions . has ( 'click' ) ;
@@ -521,9 +530,23 @@ export function generateTrigger(
521530 let onPopupMouseLeave : VoidFunction ;
522531
523532 if ( hoverToShow ) {
524- wrapperAction ( 'onMouseEnter' , true , mouseEnterDelay , ( event ) => {
525- setMousePosByEvent ( event ) ;
526- } ) ;
533+ // Compatible with old browser which not support pointer event
534+ wrapperAction < React . MouseEvent > (
535+ 'onMouseEnter' ,
536+ true ,
537+ mouseEnterDelay ,
538+ ( event ) => {
539+ setMousePosByEvent ( event ) ;
540+ } ,
541+ ) ;
542+ wrapperAction < React . PointerEvent > (
543+ 'onPointerEnter' ,
544+ true ,
545+ mouseEnterDelay ,
546+ ( event ) => {
547+ setMousePosByEvent ( event ) ;
548+ } ,
549+ ) ;
527550 onPopupMouseEnter = ( ) => {
528551 // Only trigger re-open when popup is visible
529552 if ( mergedOpen || inMotion ) {
@@ -542,6 +565,7 @@ export function generateTrigger(
542565
543566 if ( hoverToHide ) {
544567 wrapperAction ( 'onMouseLeave' , false , mouseLeaveDelay ) ;
568+ wrapperAction ( 'onPointerLeave' , false , mouseLeaveDelay ) ;
545569 onPopupMouseLeave = ( ) => {
546570 triggerOpen ( false , mouseLeaveDelay ) ;
547571 } ;
0 commit comments