@@ -123,6 +123,7 @@ export interface TriggerProps {
123123 /**
124124 * @private Bump fixed position at bottom in mobile.
125125 * Will replace the config of root props.
126+ * This will directly trade as mobile view which will not check what real is.
126127 * This is internal usage currently, do not use in your prod.
127128 */
128129 mobile ?: MobileConfig ;
@@ -250,7 +251,19 @@ export function generateTrigger(
250251 // ========================== Children ==========================
251252 const child = React . Children . only ( children ) as React . ReactElement ;
252253 const originChildProps = child ?. props || { } ;
253- const cloneProps : typeof originChildProps = { } ;
254+ const cloneProps : Pick <
255+ React . HTMLAttributes < HTMLElement > ,
256+ | 'onClick'
257+ | 'onTouchStart'
258+ | 'onMouseEnter'
259+ | 'onMouseLeave'
260+ | 'onMouseMove'
261+ | 'onPointerEnter'
262+ | 'onPointerLeave'
263+ | 'onFocus'
264+ | 'onBlur'
265+ | 'onContextMenu'
266+ > = { } ;
254267
255268 const inPopupOrChild = useEvent ( ( ele : EventTarget ) => {
256269 const childDOM = targetEle ;
@@ -381,7 +394,6 @@ export function generateTrigger(
381394 ) ;
382395
383396 const [ showActions , hideActions ] = useAction (
384- isMobile ,
385397 action ,
386398 showAction ,
387399 hideAction ,
@@ -483,22 +495,52 @@ export function generateTrigger(
483495 // =========================== Action ===========================
484496 /**
485497 * Util wrapper for trigger action
498+ * @param eventName Listen event name
499+ * @param nextOpen Next open state after trigger
500+ * @param delay Delay to trigger open change
501+ * @param callback Callback if current event need additional action
502+ * @param ignoreCheck Ignore current event if check return true
486503 */
487504 function wrapperAction < Event extends React . SyntheticEvent > (
488505 eventName : string ,
489506 nextOpen : boolean ,
490507 delay ?: number ,
491- preEvent ?: ( event : Event ) => void ,
508+ callback ?: ( event : Event ) => void ,
509+ ignoreCheck ?: ( ) => boolean ,
492510 ) {
493511 cloneProps [ eventName ] = ( event : any , ...args : any [ ] ) => {
494- preEvent ?.( event ) ;
495- triggerOpen ( nextOpen , delay ) ;
512+ if ( ! ignoreCheck || ! ignoreCheck ( ) ) {
513+ callback ?.( event ) ;
514+ triggerOpen ( nextOpen , delay ) ;
515+ }
496516
497517 // Pass to origin
498518 originChildProps [ eventName ] ?.( event , ...args ) ;
499519 } ;
500520 }
501521
522+ // ======================= Action: Touch ========================
523+ const touchToShow = showActions . has ( 'touch' ) ;
524+ const touchToHide = hideActions . has ( 'touch' ) ;
525+
526+ /** Used for prevent `hover` event conflict with mobile env */
527+ const touchedRef = React . useRef ( false ) ;
528+
529+ if ( touchToShow || touchToHide ) {
530+ cloneProps . onTouchStart = ( ...args : any [ ] ) => {
531+ touchedRef . current = true ;
532+
533+ if ( openRef . current && touchToHide ) {
534+ triggerOpen ( false ) ;
535+ } else if ( ! openRef . current && touchToShow ) {
536+ triggerOpen ( true ) ;
537+ }
538+
539+ // Pass to origin
540+ originChildProps . onTouchStart ?.( ...args ) ;
541+ } ;
542+ }
543+
502544 // ======================= Action: Click ========================
503545 if ( clickToShow || clickToHide ) {
504546 cloneProps . onClick = (
@@ -514,13 +556,14 @@ export function generateTrigger(
514556
515557 // Pass to origin
516558 originChildProps . onClick ?.( event , ...args ) ;
559+ touchedRef . current = false ;
517560 } ;
518561 }
519562
520563 // Click to hide is special action since click popup element should not hide
521564 const onPopupPointerDown = useWinClick (
522565 mergedOpen ,
523- clickToHide ,
566+ clickToHide || touchToHide ,
524567 targetEle ,
525568 popupEle ,
526569 mask ,
@@ -536,24 +579,31 @@ export function generateTrigger(
536579 let onPopupMouseEnter : React . MouseEventHandler < HTMLDivElement > ;
537580 let onPopupMouseLeave : VoidFunction ;
538581
582+ const ignoreMouseTrigger = ( ) => {
583+ return touchedRef . current ;
584+ } ;
585+
539586 if ( hoverToShow ) {
587+ const onMouseEnterCallback = ( event : React . MouseEvent ) => {
588+ setMousePosByEvent ( event ) ;
589+ } ;
590+
540591 // Compatible with old browser which not support pointer event
541592 wrapperAction < React . MouseEvent > (
542593 'onMouseEnter' ,
543594 true ,
544595 mouseEnterDelay ,
545- ( event ) => {
546- setMousePosByEvent ( event ) ;
547- } ,
596+ onMouseEnterCallback ,
597+ ignoreMouseTrigger ,
548598 ) ;
549599 wrapperAction < React . PointerEvent > (
550600 'onPointerEnter' ,
551601 true ,
552602 mouseEnterDelay ,
553- ( event ) => {
554- setMousePosByEvent ( event ) ;
555- } ,
603+ onMouseEnterCallback ,
604+ ignoreMouseTrigger ,
556605 ) ;
606+
557607 onPopupMouseEnter = ( event ) => {
558608 // Only trigger re-open when popup is visible
559609 if (
@@ -567,15 +617,27 @@ export function generateTrigger(
567617 // Align Point
568618 if ( alignPoint ) {
569619 cloneProps . onMouseMove = ( event : React . MouseEvent ) => {
570- // setMousePosByEvent(event);
571620 originChildProps . onMouseMove ?.( event ) ;
572621 } ;
573622 }
574623 }
575624
576625 if ( hoverToHide ) {
577- wrapperAction ( 'onMouseLeave' , false , mouseLeaveDelay ) ;
578- wrapperAction ( 'onPointerLeave' , false , mouseLeaveDelay ) ;
626+ wrapperAction (
627+ 'onMouseLeave' ,
628+ false ,
629+ mouseLeaveDelay ,
630+ undefined ,
631+ ignoreMouseTrigger ,
632+ ) ;
633+ wrapperAction (
634+ 'onPointerLeave' ,
635+ false ,
636+ mouseLeaveDelay ,
637+ undefined ,
638+ ignoreMouseTrigger ,
639+ ) ;
640+
579641 onPopupMouseLeave = ( ) => {
580642 triggerOpen ( false , mouseLeaveDelay ) ;
581643 } ;
0 commit comments