1919 */
2020import { useEffect , forwardRef , ReactNode , useContext , useCallback , useRef , useMemo , createElement } from 'react'
2121import { StyleSheet , NativeSyntheticEvent , View , LayoutChangeEvent } from 'react-native'
22- import { getCustomEvent } from './getInnerListeners'
22+ import useInnerProps , { getCustomEvent } from './getInnerListeners'
2323import useNodesRef , { HandlerRef } from './useNodesRef'
2424import { MovableAreaContext } from './context'
25- import { useTransformStyle , splitProps , splitStyle , HIDDEN_STYLE , wrapChildren , GestureHandler , flatGesture , extendObject } from './utils'
25+ import { useTransformStyle , splitProps , splitStyle , HIDDEN_STYLE , wrapChildren , GestureHandler , flatGesture , extendObject , omit } from './utils'
2626import { GestureDetector , Gesture , GestureTouchEvent , GestureStateChangeEvent , PanGestureHandlerEventPayload , PanGesture } from 'react-native-gesture-handler'
2727import Animated , {
2828 useSharedValue ,
@@ -33,6 +33,7 @@ import Animated, {
3333 useAnimatedReaction ,
3434 withSpring
3535} from 'react-native-reanimated'
36+ import { collectDataset , noop } from '@mpxjs/utils'
3637
3738interface MovableViewProps {
3839 children : ReactNode ;
@@ -42,17 +43,22 @@ interface MovableViewProps {
4243 y ?: number ;
4344 disabled ?: boolean ;
4445 animation ?: boolean ;
46+ id ?: string ;
4547 bindchange ?: ( event : unknown ) => void ;
46- bindtouchstart ?: ( event : NativeSyntheticEvent < TouchEvent > ) => void ;
47- catchtouchstart ?: ( event : NativeSyntheticEvent < TouchEvent > ) => void ;
48- bindtouchmove ?: ( event : NativeSyntheticEvent < TouchEvent > ) => void ;
49- catchtouchmove ?: ( event : NativeSyntheticEvent < TouchEvent > ) => void ;
50- catchtouchend ?: ( event : NativeSyntheticEvent < TouchEvent > ) => void ;
51- bindtouchend ?: ( event : NativeSyntheticEvent < TouchEvent > ) => void ;
52- bindhtouchmove ?: ( event : NativeSyntheticEvent < TouchEvent > ) => void ;
53- bindvtouchmove ?: ( event : NativeSyntheticEvent < TouchEvent > ) => void ;
54- catchhtouchmove ?: ( event : NativeSyntheticEvent < TouchEvent > ) => void ;
55- catchvtouchmove ?: ( event : NativeSyntheticEvent < TouchEvent > ) => void ;
48+ bindtouchstart ?: ( event : GestureTouchEvent ) => void ;
49+ catchtouchstart ?: ( event : GestureTouchEvent ) => void ;
50+ bindtouchmove ?: ( event : GestureTouchEvent ) => void ;
51+ catchtouchmove ?: ( event : GestureTouchEvent ) => void ;
52+ catchtouchend ?: ( event : GestureTouchEvent ) => void ;
53+ bindtouchend ?: ( event : GestureTouchEvent ) => void ;
54+ bindhtouchmove ?: ( event : GestureTouchEvent ) => void ;
55+ bindvtouchmove ?: ( event : GestureTouchEvent ) => void ;
56+ catchhtouchmove ?: ( event : GestureTouchEvent ) => void ;
57+ catchvtouchmove ?: ( event : GestureTouchEvent ) => void ;
58+ bindlongpress ?: ( event : GestureTouchEvent ) => void ;
59+ catchlongpress ?: ( event : GestureTouchEvent ) => void ;
60+ bindtap ?: ( event : GestureTouchEvent ) => void ;
61+ catchtap ?: ( event : GestureTouchEvent ) => void ;
5662 onLayout ?: ( event : LayoutChangeEvent ) => void ;
5763 'out-of-bounds' ?: boolean ;
5864 'wait-for' ?: Array < GestureHandler > ;
@@ -153,10 +159,10 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
153159 } )
154160
155161 const hasSimultaneousHandlersChanged = prevSimultaneousHandlersRef . current . length !== ( originSimultaneousHandlers ?. length || 0 ) ||
156- ( originSimultaneousHandlers || [ ] ) . some ( ( handler , index ) => handler !== prevSimultaneousHandlersRef . current [ index ] )
162+ ( originSimultaneousHandlers || [ ] ) . some ( ( handler , index ) => handler !== prevSimultaneousHandlersRef . current [ index ] )
157163
158164 const hasWaitForHandlersChanged = prevWaitForHandlersRef . current . length !== ( waitFor ?. length || 0 ) ||
159- ( waitFor || [ ] ) . some ( ( handler , index ) => handler !== prevWaitForHandlersRef . current [ index ] )
165+ ( waitFor || [ ] ) . some ( ( handler , index ) => handler !== prevWaitForHandlersRef . current [ index ] )
160166
161167 if ( hasSimultaneousHandlersChanged || hasWaitForHandlersChanged ) {
162168 gestureSwitch . current = ! gestureSwitch . current
@@ -333,57 +339,77 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
333339 props . onLayout && props . onLayout ( e )
334340 }
335341
336- const extendEvent = useCallback ( ( e : any ) => {
337- 'worklet'
342+ const extendEvent = useCallback ( ( e : any , obj ?: Record < string , any > ) => {
338343 const touchArr = [ e . changedTouches , e . allTouches ]
339344 touchArr . forEach ( touches => {
340345 touches && touches . forEach ( ( item : { absoluteX : number ; absoluteY : number ; pageX : number ; pageY : number } ) => {
341346 item . pageX = item . absoluteX
342347 item . pageY = item . absoluteY
343348 } )
344349 } )
345- e . touches = e . allTouches
350+ Object . assign ( e , {
351+ touches : e . allTouches ,
352+ detail : {
353+ x : e . changedTouches [ 0 ] . absoluteX ,
354+ y : e . changedTouches [ 0 ] . absoluteY
355+ } ,
356+ currentTarget : {
357+ id : props . id || '' ,
358+ dataset : collectDataset ( props ) ,
359+ offsetLeft : 0 ,
360+ offsetTop : 0
361+ }
362+ } , obj )
346363 } , [ ] )
347364
348- const gesture = useMemo ( ( ) => {
349- const handleTriggerStart = ( e : any ) => {
350- 'worklet'
351- extendEvent ( e )
352- bindtouchstart && runOnJS ( bindtouchstart ) ( e )
353- catchtouchstart && runOnJS ( catchtouchstart ) ( e )
354- }
355-
356- const handleTriggerMove = ( e : any ) => {
357- 'worklet'
358- extendEvent ( e )
359- const hasTouchmove = ! ! bindhtouchmove || ! ! bindvtouchmove || ! ! bindtouchmove
360- const hasCatchTouchmove = ! ! catchhtouchmove || ! ! catchvtouchmove || ! ! catchtouchmove
365+ const triggerStartOnJS = ( { e } : { e : GestureTouchEvent } ) => {
366+ extendEvent ( e )
367+ bindtouchstart && bindtouchstart ( e )
368+ catchtouchstart && catchtouchstart ( e )
369+ }
361370
362- if ( hasTouchmove ) {
363- if ( touchEvent . value === 'htouchmove' ) {
364- bindhtouchmove && runOnJS ( bindhtouchmove ) ( e )
365- } else if ( touchEvent . value === 'vtouchmove ' ) {
366- bindvtouchmove && runOnJS ( bindvtouchmove ) ( e )
367- }
368- bindtouchmove && runOnJS ( bindtouchmove ) ( e )
371+ const triggerMoveOnJS = ( { e , hasTouchmove, hasCatchTouchmove , touchEvent } : { e : GestureTouchEvent ; hasTouchmove : boolean ; hasCatchTouchmove : boolean ; touchEvent : string } ) => {
372+ extendEvent ( e )
373+ if ( hasTouchmove ) {
374+ if ( touchEvent === 'htouchmove ' ) {
375+ bindhtouchmove && bindhtouchmove ( e )
376+ } else if ( touchEvent === 'vtouchmove' ) {
377+ bindvtouchmove && bindvtouchmove ( e )
369378 }
379+ bindtouchmove && bindtouchmove ( e )
380+ }
370381
371- if ( hasCatchTouchmove ) {
372- if ( touchEvent . value === 'htouchmove' ) {
373- catchhtouchmove && runOnJS ( catchhtouchmove ) ( e )
374- } else if ( touchEvent . value === 'vtouchmove' ) {
375- catchvtouchmove && runOnJS ( catchvtouchmove ) ( e )
376- }
377- catchtouchmove && runOnJS ( catchtouchmove ) ( e )
382+ if ( hasCatchTouchmove ) {
383+ if ( touchEvent === 'htouchmove' ) {
384+ catchhtouchmove && catchhtouchmove ( e )
385+ } else if ( touchEvent === 'vtouchmove' ) {
386+ catchvtouchmove && catchvtouchmove ( e )
378387 }
388+ catchtouchmove && catchtouchmove ( e )
379389 }
390+ }
391+
392+ const triggerEndOnJS = ( { e } : { e : GestureTouchEvent } ) => {
393+ extendEvent ( e )
394+ bindtouchend && bindtouchend ( e )
395+ catchtouchend && catchtouchend ( e )
396+ }
380397
381- const handleTriggerEnd = ( e : any ) => {
398+ const gesture = useMemo ( ( ) => {
399+ const handleTriggerMove = ( e : GestureTouchEvent ) => {
382400 'worklet'
383- extendEvent ( e )
384- bindtouchend && runOnJS ( bindtouchend ) ( e )
385- catchtouchend && runOnJS ( catchtouchend ) ( e )
401+ const hasTouchmove = ! ! bindhtouchmove || ! ! bindvtouchmove || ! ! bindtouchmove
402+ const hasCatchTouchmove = ! ! catchhtouchmove || ! ! catchvtouchmove || ! ! catchtouchmove
403+ if ( hasTouchmove || hasCatchTouchmove ) {
404+ runOnJS ( triggerMoveOnJS ) ( {
405+ e,
406+ touchEvent : touchEvent . value ,
407+ hasTouchmove,
408+ hasCatchTouchmove
409+ } )
410+ }
386411 }
412+
387413 const gesturePan = Gesture . Pan ( )
388414 . onTouchesDown ( ( e : GestureTouchEvent ) => {
389415 'worklet'
@@ -393,12 +419,14 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
393419 x : changedTouches . x ,
394420 y : changedTouches . y
395421 }
396- handleTriggerStart ( e )
422+ if ( bindtouchstart || catchtouchstart ) {
423+ runOnJS ( triggerStartOnJS ) ( { e } )
424+ }
397425 } )
398426 . onTouchesMove ( ( e : GestureTouchEvent ) => {
399427 'worklet'
400- isMoving . value = true
401428 const changedTouches = e . changedTouches [ 0 ] || { x : 0 , y : 0 }
429+ isMoving . value = true
402430 if ( isFirstTouch . value ) {
403431 touchEvent . value = Math . abs ( changedTouches . x - startPosition . value . x ) > Math . abs ( changedTouches . y - startPosition . value . y ) ? 'htouchmove' : 'vtouchmove'
404432 isFirstTouch . value = false
@@ -430,7 +458,9 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
430458 'worklet'
431459 isFirstTouch . value = true
432460 isMoving . value = false
433- handleTriggerEnd ( e )
461+ if ( bindtouchend || catchtouchend ) {
462+ runOnJS ( triggerEndOnJS ) ( { e } )
463+ }
434464 if ( disabled ) return
435465 if ( ! inertia ) {
436466 const { x, y } = checkBoundaryPosition ( { positionX : offsetX . value , positionY : offsetY . value } )
@@ -454,8 +484,8 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
454484 } )
455485 . onFinalize ( ( e : GestureStateChangeEvent < PanGestureHandlerEventPayload > ) => {
456486 'worklet'
457- if ( ! inertia || disabled || ! animation ) return
458487 isMoving . value = false
488+ if ( ! inertia || disabled || ! animation ) return
459489 if ( direction === 'horizontal' || direction === 'all' ) {
460490 xInertialMotion . value = true
461491 offsetX . value = withDecay ( {
@@ -497,35 +527,50 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
497527 }
498528 } )
499529
500- const injectCatchEvent = ( props : Record < string , any > ) => {
501- const eventHandlers : Record < string , any > = { }
502- const catchEventList = [
503- { name : 'onTouchStart' , value : [ 'catchtouchstart' ] } ,
504- { name : 'onTouchMove' , value : [ 'catchtouchmove' , 'catchvtouchmove' , 'catchhtouchmove' ] } ,
505- { name : 'onTouchEnd' , value : [ 'catchtouchend' ] }
530+ const rewriteCatchEvent = ( ) => {
531+ const handlers : Record < string , typeof noop > = { }
532+
533+ const events = [
534+ { type : 'touchstart' } ,
535+ { type : 'touchmove' , alias : [ 'vtouchmove' , 'htouchmove' ] } ,
536+ { type : 'touchend' }
506537 ]
507- catchEventList . forEach ( event => {
508- event . value . forEach ( name => {
509- if ( props [ name ] && ! eventHandlers [ event . name ] ) {
510- eventHandlers [ event . name ] = ( e : NativeSyntheticEvent < TouchEvent > ) => {
511- e . stopPropagation ( )
512- }
513- }
514- } )
538+ events . forEach ( ( { type, alias = [ ] } ) => {
539+ const hasCatchEvent =
540+ props [ `catch${ type } ` as keyof typeof props ] ||
541+ alias . some ( name => props [ `catch${ name } ` as keyof typeof props ] )
542+ if ( hasCatchEvent ) handlers [ `catch${ type } ` ] = noop
515543 } )
516- return eventHandlers
544+
545+ return handlers
517546 }
518547
519- const catchEventHandlers = injectCatchEvent ( props )
520548 const layoutStyle = ! hasLayoutRef . current && hasSelfPercent ? HIDDEN_STYLE : { }
521549
550+ // bind 相关 touch 事件直接由 gesture 触发,无须重复挂载
551+ // catch 相关 touch 事件需要重写并通过 useInnerProps 注入阻止冒泡逻辑
552+ const filterProps = omit ( props , [
553+ 'bindtouchstart' ,
554+ 'bindtouchmove' ,
555+ 'bindvtouchmove' ,
556+ 'bindhtouchmove' ,
557+ 'bindtouchend' ,
558+ 'catchtouchstart' ,
559+ 'catchtouchmove' ,
560+ 'catchvtouchmove' ,
561+ 'catchhtouchmove' ,
562+ 'catchtouchend'
563+ ] )
564+
565+ const innerProps = useInnerProps ( filterProps , extendObject ( {
566+ ref : nodeRef ,
567+ onLayout : onLayout ,
568+ style : [ innerStyle , animatedStyles , layoutStyle ]
569+ } , rewriteCatchEvent ( ) ) )
570+
522571 return createElement ( GestureDetector , { gesture : gesture } , createElement (
523572 Animated . View ,
524- extendObject ( {
525- ref : nodeRef ,
526- onLayout : onLayout ,
527- style : [ innerStyle , animatedStyles , layoutStyle ]
528- } , catchEventHandlers ) ,
573+ innerProps ,
529574 wrapChildren (
530575 props ,
531576 {
0 commit comments