@mpxjs/webpack-plugin 2.10.4-beta.9 → 2.10.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/lib/index.js +10 -1
  2. package/lib/json-compiler/helper.js +1 -4
  3. package/lib/platform/style/wx/index.js +22 -21
  4. package/lib/platform/template/wx/index.js +21 -1
  5. package/lib/react/processScript.js +9 -1
  6. package/lib/react/script-helper.js +5 -1
  7. package/lib/resolver/PackageEntryPlugin.js +3 -1
  8. package/lib/runtime/components/react/dist/mpx-button.jsx +9 -4
  9. package/lib/runtime/components/react/dist/mpx-canvas/Image.js +2 -4
  10. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +20 -17
  11. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +7 -2
  12. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +7 -2
  13. package/lib/runtime/components/react/dist/mpx-icon/index.jsx +7 -2
  14. package/lib/runtime/components/react/dist/mpx-image.jsx +9 -2
  15. package/lib/runtime/components/react/dist/mpx-input.jsx +7 -2
  16. package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +1 -1
  17. package/lib/runtime/components/react/dist/mpx-label.jsx +7 -2
  18. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +7 -2
  19. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +76 -42
  20. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +11 -13
  21. package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +8 -7
  22. package/lib/runtime/components/react/dist/mpx-picker-view-column/index.jsx +28 -10
  23. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +9 -2
  24. package/lib/runtime/components/react/dist/mpx-radio.jsx +7 -2
  25. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +7 -2
  26. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +13 -4
  27. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +6 -3
  28. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +11 -9
  29. package/lib/runtime/components/react/dist/mpx-swiper.jsx +82 -36
  30. package/lib/runtime/components/react/dist/mpx-switch.jsx +7 -2
  31. package/lib/runtime/components/react/dist/mpx-text.jsx +7 -2
  32. package/lib/runtime/components/react/dist/mpx-video.jsx +7 -2
  33. package/lib/runtime/components/react/dist/mpx-view.jsx +13 -8
  34. package/lib/runtime/components/react/dist/useAnimationHooks.js +27 -4
  35. package/lib/runtime/components/react/dist/utils.jsx +87 -97
  36. package/lib/runtime/components/react/mpx-button.tsx +12 -3
  37. package/lib/runtime/components/react/mpx-canvas/Image.ts +4 -4
  38. package/lib/runtime/components/react/mpx-canvas/index.tsx +24 -17
  39. package/lib/runtime/components/react/mpx-checkbox-group.tsx +9 -1
  40. package/lib/runtime/components/react/mpx-checkbox.tsx +9 -1
  41. package/lib/runtime/components/react/mpx-icon/index.tsx +9 -1
  42. package/lib/runtime/components/react/mpx-image.tsx +38 -19
  43. package/lib/runtime/components/react/mpx-input.tsx +10 -1
  44. package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +1 -1
  45. package/lib/runtime/components/react/mpx-label.tsx +9 -1
  46. package/lib/runtime/components/react/mpx-movable-area.tsx +7 -1
  47. package/lib/runtime/components/react/mpx-movable-view.tsx +75 -42
  48. package/lib/runtime/components/react/mpx-picker/index.tsx +18 -16
  49. package/lib/runtime/components/react/mpx-picker-view/index.tsx +22 -8
  50. package/lib/runtime/components/react/mpx-picker-view-column/index.tsx +36 -32
  51. package/lib/runtime/components/react/mpx-radio-group.tsx +20 -9
  52. package/lib/runtime/components/react/mpx-radio.tsx +9 -1
  53. package/lib/runtime/components/react/mpx-rich-text/index.tsx +10 -2
  54. package/lib/runtime/components/react/mpx-scroll-view.tsx +14 -3
  55. package/lib/runtime/components/react/mpx-sticky-header.tsx +7 -4
  56. package/lib/runtime/components/react/mpx-swiper-item.tsx +11 -19
  57. package/lib/runtime/components/react/mpx-swiper.tsx +95 -38
  58. package/lib/runtime/components/react/mpx-switch.tsx +10 -2
  59. package/lib/runtime/components/react/mpx-text.tsx +10 -2
  60. package/lib/runtime/components/react/mpx-video.tsx +7 -2
  61. package/lib/runtime/components/react/mpx-view.tsx +23 -9
  62. package/lib/runtime/components/react/useAnimationHooks.ts +30 -9
  63. package/lib/runtime/components/react/utils.tsx +95 -102
  64. package/lib/runtime/components/web/mpx-web-view.vue +1 -1
  65. package/lib/runtime/mpxGlobal.js +1 -0
  66. package/lib/runtime/optionProcessor.d.ts +5 -0
  67. package/lib/template-compiler/bind-this.js +8 -7
  68. package/lib/template-compiler/compiler.js +1 -1
  69. package/lib/wxs/pre-loader.js +1 -0
  70. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  import { View } from 'react-native'
2
2
  import Animated, { useAnimatedStyle, interpolate, SharedValue } from 'react-native-reanimated'
3
- import { ReactNode, forwardRef, useRef, useContext } from 'react'
3
+ import { ReactNode, forwardRef, useRef, useContext, createElement } from 'react'
4
4
  import useInnerProps from './getInnerListeners'
5
5
  import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数
6
6
  import { useTransformStyle, splitStyle, splitProps, wrapChildren, useLayout, extendObject } from './utils'
@@ -95,24 +95,16 @@ const _SwiperItem = forwardRef<HandlerRef<View, SwiperItemProps>, SwiperItemProp
95
95
  transform: transformStyle
96
96
  })
97
97
  })
98
- return (
99
- <Animated.View
100
- {...innerProps}
101
- style={[innerStyle, layoutStyle, itemAnimatedStyle, customStyle]}
102
- data-itemId={props['item-id']}>
103
- {
104
- wrapChildren(
105
- props,
106
- {
107
- hasVarDec,
108
- varContext: varContextRef.current,
109
- textStyle,
110
- textProps
111
- }
112
- )
113
- }
114
- </Animated.View>
115
- )
98
+ const mergeProps = extendObject({}, innerProps, {
99
+ style: [innerStyle, layoutStyle, itemAnimatedStyle, customStyle],
100
+ 'data-itemId': props['item-id']
101
+ })
102
+ return createElement(Animated.View, mergeProps, wrapChildren(props, {
103
+ hasVarDec,
104
+ varContext: varContextRef.current,
105
+ textStyle,
106
+ textProps
107
+ }))
116
108
  })
117
109
 
118
110
  _SwiperItem.displayName = 'MpxSwiperItem'
@@ -1,12 +1,13 @@
1
1
  import { View, NativeSyntheticEvent, LayoutChangeEvent } from 'react-native'
2
- import { GestureDetector, Gesture } from 'react-native-gesture-handler'
2
+ import { GestureDetector, Gesture, PanGesture } from 'react-native-gesture-handler'
3
3
  import Animated, { useAnimatedStyle, useSharedValue, withTiming, Easing, runOnJS, useAnimatedReaction, cancelAnimation } from 'react-native-reanimated'
4
4
 
5
- import React, { JSX, forwardRef, useRef, useEffect, ReactNode, ReactElement, useMemo } from 'react'
5
+ import React, { JSX, forwardRef, useRef, useEffect, ReactNode, ReactElement, useMemo, createElement } from 'react'
6
6
  import useInnerProps, { getCustomEvent } from './getInnerListeners'
7
7
  import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数
8
- import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren, extendObject } from './utils'
8
+ import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren, extendObject, GestureHandler, flatGesture } from './utils'
9
9
  import { SwiperContext } from './context'
10
+ import Portal from './mpx-portal'
10
11
  /**
11
12
  * ✔ indicator-dots
12
13
  * ✔ indicator-color
@@ -45,7 +46,7 @@ interface SwiperProps {
45
46
  vertical?: boolean
46
47
  style: {
47
48
  [key: string]: any
48
- }
49
+ };
49
50
  'easing-function'?: EaseType
50
51
  'previous-margin'?: string
51
52
  'next-margin'?: string
@@ -53,8 +54,11 @@ interface SwiperProps {
53
54
  'enable-var': boolean
54
55
  'parent-font-size'?: number
55
56
  'parent-width'?: number
56
- 'parent-height'?: number
57
+ 'parent-height'?: number;
57
58
  'external-var-context'?: Record<string, any>
59
+ 'wait-for'?: Array<GestureHandler>
60
+ 'simultaneous-handlers'?: Array<GestureHandler>
61
+ disableGesture?: boolean
58
62
  bindchange?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
59
63
  }
60
64
 
@@ -126,7 +130,7 @@ const easeMap = {
126
130
 
127
131
  const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((props: SwiperProps, ref): JSX.Element => {
128
132
  const {
129
- 'indicator-dots': showsPagination,
133
+ 'indicator-dots': showPagination,
130
134
  'indicator-color': dotColor = 'rgba(0, 0, 0, .3)',
131
135
  'indicator-active-color': activeDotColor = '#000000',
132
136
  'enable-var': enableVar = false,
@@ -134,21 +138,30 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
134
138
  'parent-width': parentWidth,
135
139
  'parent-height': parentHeight,
136
140
  'external-var-context': externalVarContext,
141
+ 'simultaneous-handlers': originSimultaneousHandlers = [],
142
+ 'wait-for': waitFor = [],
137
143
  style = {},
138
144
  autoplay = false,
139
- circular = false
145
+ circular = false,
146
+ disableGesture = false
140
147
  } = props
141
148
  const easeingFunc = props['easing-function'] || 'default'
142
149
  const easeDuration = props.duration || 500
143
150
  const horizontal = props.vertical !== undefined ? !props.vertical : true
144
151
  const nodeRef = useRef<View>(null)
145
- useNodesRef<View, SwiperProps>(props, ref, nodeRef, {})
152
+ // 手势协同gesture 1.0
153
+ const swiperGestureRef = useRef<PanGesture>()
154
+ useNodesRef<View, SwiperProps>(props, ref, nodeRef, {
155
+ // scrollView内部会过滤是否绑定了gestureRef,withRef(swiperGestureRef)给gesture对象设置一个ref(2.0版本)
156
+ gestureRef: swiperGestureRef
157
+ })
146
158
  // 计算transfrom之类的
147
159
  const {
148
160
  normalStyle,
149
161
  hasVarDec,
150
162
  varContextRef,
151
163
  hasSelfPercent,
164
+ hasPositionFixed,
152
165
  setWidth,
153
166
  setHeight
154
167
  } = useTransformStyle(style, {
@@ -195,6 +208,27 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
195
208
  const moveTime = useSharedValue(0)
196
209
  const timerId = useRef(0 as number | ReturnType<typeof setTimeout>)
197
210
  const intervalTimer = props.interval || 500
211
+
212
+ const simultaneousHandlers = flatGesture(originSimultaneousHandlers)
213
+ const waitForHandlers = flatGesture(waitFor)
214
+ // 判断gesture手势是否需要协同处理、等待手势失败响应
215
+ const gestureSwitch = useRef(false)
216
+ // 初始化上一次的手势
217
+ const prevSimultaneousHandlersRef = useRef<Array<GestureHandler>>(originSimultaneousHandlers || [])
218
+ const prevWaitForHandlersRef = useRef<Array<GestureHandler>>(waitFor || [])
219
+ const hasSimultaneousHandlersChanged = prevSimultaneousHandlersRef.current.length !== (originSimultaneousHandlers?.length || 0) ||
220
+ (originSimultaneousHandlers || []).some((handler, index) => handler !== prevSimultaneousHandlersRef.current[index])
221
+
222
+ const hasWaitForHandlersChanged = prevWaitForHandlersRef.current.length !== (waitFor?.length || 0) ||
223
+ (waitFor || []).some((handler, index) => handler !== prevWaitForHandlersRef.current[index])
224
+
225
+ if (hasSimultaneousHandlersChanged || hasWaitForHandlersChanged) {
226
+ gestureSwitch.current = !gestureSwitch.current
227
+ }
228
+ // 存储上一次的手势
229
+ prevSimultaneousHandlersRef.current = originSimultaneousHandlers || []
230
+ prevWaitForHandlersRef.current = waitFor || []
231
+
198
232
  const {
199
233
  // 存储layout布局信息
200
234
  layoutRef,
@@ -248,7 +282,6 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
248
282
  })
249
283
 
250
284
  function renderPagination () {
251
- if (children.length <= 1) return null
252
285
  const activeColor = activeDotColor || '#007aff'
253
286
  const unActionColor = dotColor || 'rgba(0,0,0,.2)'
254
287
  // 正常渲染所有dots
@@ -491,7 +524,6 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
491
524
  offset.value = getOffset(currentIndex.value, step.value)
492
525
  }
493
526
  }, [circular, preMargin])
494
-
495
527
  const { gestureHandler } = useMemo(() => {
496
528
  function getTargetPosition (eventData: EventDataType) {
497
529
  'worklet'
@@ -574,6 +606,15 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
574
606
  })
575
607
  }
576
608
  }
609
+ function handleBackInit () {
610
+ 'worklet'
611
+ // 微信的效果
612
+ // 1. 只有一个元素,即使设置了circular,也不会产生循环的效果,2. 可以响应手势,但是会有回弹的效果
613
+ offset.value = withTiming(0, {
614
+ duration: easeDuration,
615
+ easing: easeMap[easeingFunc]
616
+ })
617
+ }
577
618
  function handleBack (eventData: EventDataType) {
578
619
  'worklet'
579
620
  const { translation } = eventData
@@ -675,7 +716,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
675
716
  return
676
717
  }
677
718
  const { isBoundary, resetOffset } = reachBoundary(eventData)
678
- if (isBoundary && circularShared.value) {
719
+ if (childrenLength.value > 1 && isBoundary && circularShared.value) {
679
720
  offset.value = resetOffset
680
721
  } else {
681
722
  offset.value = moveDistance + offset.value
@@ -691,6 +732,9 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
691
732
  const eventData = {
692
733
  translation: moveDistance
693
734
  }
735
+ if (childrenLength.value === 1) {
736
+ return handleBackInit()
737
+ }
694
738
  // 用户手指按下起来, 需要计算正确的位置, 比如在滑动过程中突然按下然后起来,需要计算到正确的位置
695
739
  if (!circularShared.value && !canMove(eventData)) {
696
740
  return
@@ -702,10 +746,25 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
702
746
  handleEnd(eventData)
703
747
  }
704
748
  })
749
+ .withRef(swiperGestureRef)
750
+ // swiper横向,当y轴滑动5像素手势失效;swiper纵向只响应swiper的滑动事件
751
+ if (dir === 'x') {
752
+ gesturePan.activeOffsetX([-2, 2]).failOffsetY([-5, 5])
753
+ } else {
754
+ gesturePan.activeOffsetY([-2, 2]).failOffsetX([-5, 5])
755
+ }
756
+ // 手势协同2.0
757
+ if (simultaneousHandlers && simultaneousHandlers.length) {
758
+ gesturePan.simultaneousWithExternalGesture(...simultaneousHandlers)
759
+ }
760
+
761
+ if (waitForHandlers && waitForHandlers.length) {
762
+ gesturePan.requireExternalGestureToFail(...waitForHandlers)
763
+ }
705
764
  return {
706
765
  gestureHandler: gesturePan
707
766
  }
708
- }, [])
767
+ }, [gestureSwitch.current])
709
768
 
710
769
  const animatedStyles = useAnimatedStyle(() => {
711
770
  if (dir === 'x') {
@@ -715,34 +774,32 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
715
774
  }
716
775
  })
717
776
 
718
- function renderSwiper () {
719
- const arrPages: Array<ReactNode> | ReactNode = renderItems()
720
- return (<View style={[normalStyle, layoutStyle, styles.swiper]} {...layoutProps} {...innerProps}>
721
- <Animated.View style={[{
722
- flexDirection: dir === 'x' ? 'row' : 'column',
723
- width: '100%',
724
- height: '100%'
725
- }, animatedStyles]}>
726
- {wrapChildren({
727
- children: arrPages
728
- }, {
729
- hasVarDec,
730
- varContext: varContextRef.current,
731
- textStyle,
732
- textProps
733
- })}
734
- </Animated.View>
735
- {showsPagination && renderPagination()}
736
- </View>)
777
+ let finalComponent: JSX.Element
778
+ const arrPages: Array<ReactNode> | ReactNode = renderItems()
779
+ const mergeProps = Object.assign({
780
+ style: [normalStyle, layoutStyle, styles.swiper]
781
+ }, layoutProps, innerProps)
782
+ const animateComponent = createElement(Animated.View, {
783
+ style: [{ flexDirection: dir === 'x' ? 'row' : 'column', width: '100%', height: '100%' }, animatedStyles]
784
+ }, wrapChildren({
785
+ children: arrPages
786
+ }, {
787
+ hasVarDec,
788
+ varContext: varContextRef.current,
789
+ textStyle,
790
+ textProps
791
+ }))
792
+ const renderChildrens = showPagination ? [animateComponent, renderPagination()] : animateComponent
793
+ finalComponent = createElement(View, mergeProps, renderChildrens)
794
+ if (!disableGesture) {
795
+ finalComponent = createElement(GestureDetector, {
796
+ gesture: gestureHandler
797
+ }, finalComponent)
737
798
  }
738
-
739
- if (children.length === 1) {
740
- return renderSwiper()
741
- } else {
742
- return (<GestureDetector gesture={gestureHandler}>
743
- {renderSwiper()}
744
- </GestureDetector>)
799
+ if (hasPositionFixed) {
800
+ finalComponent = createElement(Portal, null, finalComponent)
745
801
  }
802
+ return finalComponent
746
803
  })
747
804
  SwiperWrapper.displayName = 'MpxSwiperWrapper'
748
805
 
@@ -11,6 +11,7 @@ import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数
11
11
  import useInnerProps, { getCustomEvent } from './getInnerListeners'
12
12
 
13
13
  import CheckBox from './mpx-checkbox'
14
+ import Portal from './mpx-portal'
14
15
  import { FormContext, FormFieldValue } from './context'
15
16
  import { useTransformStyle, useLayout, extendObject } from './utils'
16
17
 
@@ -62,7 +63,8 @@ const _Switch = forwardRef<HandlerRef<Switch, _SwitchProps>, _SwitchProps>((prop
62
63
  normalStyle,
63
64
  hasSelfPercent,
64
65
  setWidth,
65
- setHeight
66
+ setHeight,
67
+ hasPositionFixed
66
68
  } = useTransformStyle(style, {
67
69
  enableVar,
68
70
  externalVarContext,
@@ -151,7 +153,7 @@ const _Switch = forwardRef<HandlerRef<Switch, _SwitchProps>, _SwitchProps>((prop
151
153
  )
152
154
  }
153
155
 
154
- return createElement(
156
+ let finalComponent: JSX.Element = createElement(
155
157
  Switch,
156
158
  extendObject({}, innerProps, {
157
159
  style: normalStyle,
@@ -161,6 +163,12 @@ const _Switch = forwardRef<HandlerRef<Switch, _SwitchProps>, _SwitchProps>((prop
161
163
  ios_backgroundColor: '#FFF'
162
164
  })
163
165
  )
166
+
167
+ if (hasPositionFixed) {
168
+ finalComponent = createElement(Portal, null, finalComponent)
169
+ }
170
+
171
+ return finalComponent
164
172
  })
165
173
 
166
174
  _Switch.displayName = 'MpxSwitch'
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import { Text, TextStyle, TextProps } from 'react-native'
8
8
  import { useRef, forwardRef, ReactNode, JSX, createElement } from 'react'
9
+ import Portal from './mpx-portal'
9
10
  import useInnerProps from './getInnerListeners'
10
11
  import useNodesRef, { HandlerRef } from './useNodesRef' // 引入辅助函数
11
12
  import { useTransformStyle, wrapChildren, extendObject } from './utils'
@@ -38,7 +39,8 @@ const _Text = forwardRef<HandlerRef<Text, _TextProps>, _TextProps>((props, ref):
38
39
  const {
39
40
  normalStyle,
40
41
  hasVarDec,
41
- varContextRef
42
+ varContextRef,
43
+ hasPositionFixed
42
44
  } = useTransformStyle(style, {
43
45
  enableVar,
44
46
  externalVarContext,
@@ -68,13 +70,19 @@ const _Text = forwardRef<HandlerRef<Text, _TextProps>, _TextProps>((props, ref):
68
70
  ]
69
71
  )
70
72
 
71
- return createElement(Text, innerProps, wrapChildren(
73
+ let finalComponent:JSX.Element = createElement(Text, innerProps, wrapChildren(
72
74
  props,
73
75
  {
74
76
  hasVarDec,
75
77
  varContext: varContextRef.current
76
78
  }
77
79
  ))
80
+
81
+ if (hasPositionFixed) {
82
+ finalComponent = createElement(Portal, null, finalComponent)
83
+ }
84
+
85
+ return finalComponent
78
86
  })
79
87
 
80
88
  _Text.displayName = 'MpxText'
@@ -74,6 +74,7 @@ import {
74
74
  } from './utils'
75
75
  import useInnerProps, { getCustomEvent } from './getInnerListeners'
76
76
  import useNodesRef, { HandlerRef } from './useNodesRef'
77
+ import Portal from './mpx-portal'
77
78
 
78
79
  interface VideoProps {
79
80
  src: string
@@ -170,7 +171,7 @@ const MpxVideo = forwardRef<HandlerRef<View, VideoProps>, VideoProps>((videoProp
170
171
 
171
172
  propsRef.current = props
172
173
 
173
- const { normalStyle, hasSelfPercent, setWidth, setHeight } =
174
+ const { normalStyle, hasSelfPercent, setWidth, setHeight, hasPositionFixed } =
174
175
  useTransformStyle(extendObject({}, styles.container, style), {
175
176
  enableVar,
176
177
  externalVarContext,
@@ -381,9 +382,13 @@ const MpxVideo = forwardRef<HandlerRef<View, VideoProps>, VideoProps>((videoProp
381
382
  ],
382
383
  { layoutRef }
383
384
  )
384
- return createElement(View, { style: extendObject({}, normalStyle, layoutStyle), ref: viewRef },
385
+ let videoComponent: JSX.Element = createElement(View, { style: extendObject({}, normalStyle, layoutStyle), ref: viewRef },
385
386
  createElement(Video, innerProps)
386
387
  )
388
+ if (hasPositionFixed) {
389
+ videoComponent = createElement(Portal, null, videoComponent)
390
+ }
391
+ return videoComponent
387
392
  })
388
393
 
389
394
  export default MpxVideo
@@ -13,7 +13,7 @@ import type { AnimationProp } from './useAnimationHooks'
13
13
  import { ExtendedViewStyle } from './types/common'
14
14
  import useNodesRef, { HandlerRef } from './useNodesRef'
15
15
  import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage, pickStyle, extendObject, useHover } from './utils'
16
- import { error } from '@mpxjs/utils'
16
+ import { error, isFunction } from '@mpxjs/utils'
17
17
  import LinearGradient from 'react-native-linear-gradient'
18
18
  import { GestureDetector, PanGesture } from 'react-native-gesture-handler'
19
19
  import Portal from './mpx-portal'
@@ -36,6 +36,8 @@ export interface _ViewProps extends ViewProps {
36
36
  bindtouchstart?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
37
37
  bindtouchmove?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
38
38
  bindtouchend?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
39
+ bindtransitionend?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
40
+ catchtransitionend?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
39
41
  }
40
42
 
41
43
  type Handler = (...args: any[]) => void
@@ -636,10 +638,14 @@ function useWrapImage (imageStyle?: ExtendedViewStyle, innerStyle?: Record<strin
636
638
  }
637
639
  }
638
640
 
639
- return <View key='backgroundImage' {...needLayout ? { onLayout } : null} style={{ ...inheritStyle(innerStyle), ...StyleSheet.absoluteFillObject, overflow: 'hidden' }}>
640
- {show && type === 'linear' && <LinearGradient useAngle={true} {...imageStyleToProps(preImageInfo, sizeInfo.current as Size, layoutInfo.current as Size)} />}
641
- {show && type === 'image' && (renderImage(imageStyleToProps(preImageInfo, sizeInfo.current as Size, layoutInfo.current as Size), enableFastImage))}
642
- </View>
641
+ const backgroundProps: ViewProps = extendObject({ key: 'backgroundImage' }, needLayout ? { onLayout } : {},
642
+ { style: extendObject({}, inheritStyle(innerStyle), StyleSheet.absoluteFillObject, { overflow: 'hidden' as const }) }
643
+ )
644
+
645
+ return createElement(View, backgroundProps,
646
+ show && type === 'linear' && createElement(LinearGradient, extendObject({ useAngle: true }, imageStyleToProps(preImageInfo, sizeInfo.current as Size, layoutInfo.current as Size))),
647
+ show && type === 'image' && renderImage(imageStyleToProps(preImageInfo, sizeInfo.current as Size, layoutInfo.current as Size), enableFastImage)
648
+ )
643
649
  }
644
650
 
645
651
  interface WrapChildrenConfig {
@@ -683,7 +689,9 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
683
689
  'parent-font-size': parentFontSize,
684
690
  'parent-width': parentWidth,
685
691
  'parent-height': parentHeight,
686
- animation
692
+ animation,
693
+ catchtransitionend,
694
+ bindtransitionend
687
695
  } = props
688
696
 
689
697
  // 默认样式
@@ -737,11 +745,17 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, r
737
745
  } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef })
738
746
 
739
747
  const viewStyle = extendObject({}, innerStyle, layoutStyle)
740
-
748
+ const transitionend = isFunction(catchtransitionend)
749
+ ? catchtransitionend
750
+ : isFunction(bindtransitionend)
751
+ ? bindtransitionend
752
+ : undefined
741
753
  const { enableStyleAnimation, animationStyle } = useAnimationHooks({
742
- enableAnimation,
754
+ layoutRef,
743
755
  animation,
744
- style: viewStyle
756
+ enableAnimation,
757
+ style: viewStyle,
758
+ transitionend
745
759
  })
746
760
 
747
761
  const innerProps = useInnerProps(
@@ -1,5 +1,6 @@
1
1
  import { useEffect, useMemo, useRef } from 'react'
2
- import { TransformsStyle } from 'react-native'
2
+ import type { MutableRefObject } from 'react'
3
+ import type { NativeSyntheticEvent, TransformsStyle } from 'react-native'
3
4
  import {
4
5
  Easing,
5
6
  useSharedValue,
@@ -9,11 +10,10 @@ import {
9
10
  withDelay,
10
11
  makeMutable,
11
12
  cancelAnimation,
12
- SharedValue,
13
- WithTimingConfig,
14
- AnimationCallback
13
+ runOnJS
15
14
  } from 'react-native-reanimated'
16
- import { error, hasOwn } from '@mpxjs/utils'
15
+ import type { AnimationCallback, WithTimingConfig, SharedValue, AnimatableValue } from 'react-native-reanimated'
16
+ import { error, hasOwn, collectDataset } from '@mpxjs/utils'
17
17
  import { ExtendedViewStyle } from './types/common'
18
18
  import type { _ViewProps } from './mpx-view'
19
19
 
@@ -175,9 +175,8 @@ function getTransformObj (transforms: { [propName: string]: string | number }[])
175
175
  }, {} as { [propName: string]: string | number })
176
176
  }
177
177
 
178
- export default function useAnimationHooks<T, P> (props: _ViewProps & { enableAnimation?: boolean }) {
179
- const { style = {}, animation, enableAnimation } = props
180
-
178
+ export default function useAnimationHooks<T, P> (props: _ViewProps & { enableAnimation?: boolean, layoutRef: MutableRefObject<any>, transitionend?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void }) {
179
+ const { style = {}, animation, enableAnimation, transitionend, layoutRef } = props
181
180
  const enableStyleAnimation = enableAnimation || !!animation
182
181
  const enableAnimationRef = useRef(enableStyleAnimation)
183
182
  if (enableAnimationRef.current !== enableStyleAnimation) {
@@ -285,10 +284,32 @@ export default function useAnimationHooks<T, P> (props: _ViewProps & { enableAni
285
284
  })
286
285
  })
287
286
  }
287
+ function withTimingCallback (finished?: boolean, current?: AnimatableValue, duration?: number) {
288
+ if (!transitionend) return
289
+ const target = {
290
+ id: animation?.id || -1,
291
+ dataset: collectDataset(props),
292
+ offsetLeft: layoutRef?.current?.offsetLeft || 0,
293
+ offsetTop: layoutRef?.current?.offsetTop || 0
294
+ }
295
+ transitionend({
296
+ type: 'transitionend',
297
+ // elapsedTime 对齐wx 单位s
298
+ detail: { elapsedTime: duration ? duration / 1000 : 0, finished, current },
299
+ target,
300
+ currentTarget: target,
301
+ timeStamp: Date.now()
302
+ })
303
+ }
288
304
  // 创建单个animation
289
305
  function getAnimation ({ key, value }: { key: string, value: string|number }, { delay, duration, easing }: ExtendWithTimingConfig, callback?: AnimationCallback) {
290
306
  const animation = typeof callback === 'function'
291
- ? withTiming(value, { duration, easing }, callback)
307
+ ? withTiming(value, { duration, easing }, (finished, current) => {
308
+ callback(finished, current)
309
+ if (transitionend && finished) {
310
+ runOnJS(withTimingCallback)(finished, current, duration)
311
+ }
312
+ })
292
313
  : withTiming(value, { duration, easing })
293
314
  return delay ? withDelay(delay, animation) : animation
294
315
  }