@@ -123,6 +123,7 @@ export interface TriggerProps {
123
123
/**
124
124
* @private Bump fixed position at bottom in mobile.
125
125
* Will replace the config of root props.
126
+ * This will directly trade as mobile view which will not check what real is.
126
127
* This is internal usage currently, do not use in your prod.
127
128
*/
128
129
mobile ?: MobileConfig ;
@@ -250,7 +251,19 @@ export function generateTrigger(
250
251
// ========================== Children ==========================
251
252
const child = React . Children . only ( children ) as React . ReactElement ;
252
253
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
+ > = { } ;
254
267
255
268
const inPopupOrChild = useEvent ( ( ele : EventTarget ) => {
256
269
const childDOM = targetEle ;
@@ -381,7 +394,6 @@ export function generateTrigger(
381
394
) ;
382
395
383
396
const [ showActions , hideActions ] = useAction (
384
- isMobile ,
385
397
action ,
386
398
showAction ,
387
399
hideAction ,
@@ -483,22 +495,52 @@ export function generateTrigger(
483
495
// =========================== Action ===========================
484
496
/**
485
497
* 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
486
503
*/
487
504
function wrapperAction < Event extends React . SyntheticEvent > (
488
505
eventName : string ,
489
506
nextOpen : boolean ,
490
507
delay ?: number ,
491
- preEvent ?: ( event : Event ) => void ,
508
+ callback ?: ( event : Event ) => void ,
509
+ ignoreCheck ?: ( ) => boolean ,
492
510
) {
493
511
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
+ }
496
516
497
517
// Pass to origin
498
518
originChildProps [ eventName ] ?.( event , ...args ) ;
499
519
} ;
500
520
}
501
521
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
+
502
544
// ======================= Action: Click ========================
503
545
if ( clickToShow || clickToHide ) {
504
546
cloneProps . onClick = (
@@ -514,13 +556,14 @@ export function generateTrigger(
514
556
515
557
// Pass to origin
516
558
originChildProps . onClick ?.( event , ...args ) ;
559
+ touchedRef . current = false ;
517
560
} ;
518
561
}
519
562
520
563
// Click to hide is special action since click popup element should not hide
521
564
const onPopupPointerDown = useWinClick (
522
565
mergedOpen ,
523
- clickToHide ,
566
+ clickToHide || touchToHide ,
524
567
targetEle ,
525
568
popupEle ,
526
569
mask ,
@@ -536,24 +579,31 @@ export function generateTrigger(
536
579
let onPopupMouseEnter : React . MouseEventHandler < HTMLDivElement > ;
537
580
let onPopupMouseLeave : VoidFunction ;
538
581
582
+ const ignoreMouseTrigger = ( ) => {
583
+ return touchedRef . current ;
584
+ } ;
585
+
539
586
if ( hoverToShow ) {
587
+ const onMouseEnterCallback = ( event : React . MouseEvent ) => {
588
+ setMousePosByEvent ( event ) ;
589
+ } ;
590
+
540
591
// Compatible with old browser which not support pointer event
541
592
wrapperAction < React . MouseEvent > (
542
593
'onMouseEnter' ,
543
594
true ,
544
595
mouseEnterDelay ,
545
- ( event ) => {
546
- setMousePosByEvent ( event ) ;
547
- } ,
596
+ onMouseEnterCallback ,
597
+ ignoreMouseTrigger ,
548
598
) ;
549
599
wrapperAction < React . PointerEvent > (
550
600
'onPointerEnter' ,
551
601
true ,
552
602
mouseEnterDelay ,
553
- ( event ) => {
554
- setMousePosByEvent ( event ) ;
555
- } ,
603
+ onMouseEnterCallback ,
604
+ ignoreMouseTrigger ,
556
605
) ;
606
+
557
607
onPopupMouseEnter = ( event ) => {
558
608
// Only trigger re-open when popup is visible
559
609
if (
@@ -567,15 +617,27 @@ export function generateTrigger(
567
617
// Align Point
568
618
if ( alignPoint ) {
569
619
cloneProps . onMouseMove = ( event : React . MouseEvent ) => {
570
- // setMousePosByEvent(event);
571
620
originChildProps . onMouseMove ?.( event ) ;
572
621
} ;
573
622
}
574
623
}
575
624
576
625
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
+
579
641
onPopupMouseLeave = ( ) => {
580
642
triggerOpen ( false , mouseLeaveDelay ) ;
581
643
} ;
0 commit comments