@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,11 +1,12 @@
1
1
  import { View } from 'react-native';
2
2
  import { GestureDetector, Gesture } from 'react-native-gesture-handler';
3
3
  import Animated, { useAnimatedStyle, useSharedValue, withTiming, Easing, runOnJS, useAnimatedReaction, cancelAnimation } from 'react-native-reanimated';
4
- import React, { forwardRef, useRef, useEffect, useMemo } from 'react';
4
+ import React, { forwardRef, useRef, useEffect, useMemo, createElement } from 'react';
5
5
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
6
6
  import useNodesRef from './useNodesRef'; // 引入辅助函数
7
- import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren, extendObject } from './utils';
7
+ import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren, extendObject, flatGesture } from './utils';
8
8
  import { SwiperContext } from './context';
9
+ import Portal from './mpx-portal';
9
10
  /**
10
11
  * 默认的Style类型
11
12
  */
@@ -70,14 +71,19 @@ const easeMap = {
70
71
  easeInOutCubic: Easing.inOut(Easing.cubic)
71
72
  };
72
73
  const SwiperWrapper = forwardRef((props, ref) => {
73
- const { 'indicator-dots': showsPagination, 'indicator-color': dotColor = 'rgba(0, 0, 0, .3)', 'indicator-active-color': activeDotColor = '#000000', 'enable-var': enableVar = false, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'external-var-context': externalVarContext, style = {}, autoplay = false, circular = false } = props;
74
+ const { 'indicator-dots': showPagination, 'indicator-color': dotColor = 'rgba(0, 0, 0, .3)', 'indicator-active-color': activeDotColor = '#000000', 'enable-var': enableVar = false, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'external-var-context': externalVarContext, 'simultaneous-handlers': originSimultaneousHandlers = [], 'wait-for': waitFor = [], style = {}, autoplay = false, circular = false, disableGesture = false } = props;
74
75
  const easeingFunc = props['easing-function'] || 'default';
75
76
  const easeDuration = props.duration || 500;
76
77
  const horizontal = props.vertical !== undefined ? !props.vertical : true;
77
78
  const nodeRef = useRef(null);
78
- useNodesRef(props, ref, nodeRef, {});
79
+ // 手势协同gesture 1.0
80
+ const swiperGestureRef = useRef();
81
+ useNodesRef(props, ref, nodeRef, {
82
+ // scrollView内部会过滤是否绑定了gestureRef,withRef(swiperGestureRef)给gesture对象设置一个ref(2.0版本)
83
+ gestureRef: swiperGestureRef
84
+ });
79
85
  // 计算transfrom之类的
80
- const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, {
86
+ const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, hasPositionFixed, setWidth, setHeight } = useTransformStyle(style, {
81
87
  enableVar,
82
88
  externalVarContext,
83
89
  parentFontSize,
@@ -121,6 +127,23 @@ const SwiperWrapper = forwardRef((props, ref) => {
121
127
  const moveTime = useSharedValue(0);
122
128
  const timerId = useRef(0);
123
129
  const intervalTimer = props.interval || 500;
130
+ const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
131
+ const waitForHandlers = flatGesture(waitFor);
132
+ // 判断gesture手势是否需要协同处理、等待手势失败响应
133
+ const gestureSwitch = useRef(false);
134
+ // 初始化上一次的手势
135
+ const prevSimultaneousHandlersRef = useRef(originSimultaneousHandlers || []);
136
+ const prevWaitForHandlersRef = useRef(waitFor || []);
137
+ const hasSimultaneousHandlersChanged = prevSimultaneousHandlersRef.current.length !== (originSimultaneousHandlers?.length || 0) ||
138
+ (originSimultaneousHandlers || []).some((handler, index) => handler !== prevSimultaneousHandlersRef.current[index]);
139
+ const hasWaitForHandlersChanged = prevWaitForHandlersRef.current.length !== (waitFor?.length || 0) ||
140
+ (waitFor || []).some((handler, index) => handler !== prevWaitForHandlersRef.current[index]);
141
+ if (hasSimultaneousHandlersChanged || hasWaitForHandlersChanged) {
142
+ gestureSwitch.current = !gestureSwitch.current;
143
+ }
144
+ // 存储上一次的手势
145
+ prevSimultaneousHandlersRef.current = originSimultaneousHandlers || [];
146
+ prevWaitForHandlersRef.current = waitFor || [];
124
147
  const {
125
148
  // 存储layout布局信息
126
149
  layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef, onLayout: onWrapperLayout });
@@ -164,8 +187,6 @@ const SwiperWrapper = forwardRef((props, ref) => {
164
187
  }
165
188
  });
166
189
  function renderPagination() {
167
- if (children.length <= 1)
168
- return null;
169
190
  const activeColor = activeDotColor || '#007aff';
170
191
  const unActionColor = dotColor || 'rgba(0,0,0,.2)';
171
192
  // 正常渲染所有dots
@@ -490,6 +511,15 @@ const SwiperWrapper = forwardRef((props, ref) => {
490
511
  });
491
512
  }
492
513
  }
514
+ function handleBackInit() {
515
+ 'worklet';
516
+ // 微信的效果
517
+ // 1. 只有一个元素,即使设置了circular,也不会产生循环的效果,2. 可以响应手势,但是会有回弹的效果
518
+ offset.value = withTiming(0, {
519
+ duration: easeDuration,
520
+ easing: easeMap[easeingFunc]
521
+ });
522
+ }
493
523
  function handleBack(eventData) {
494
524
  'worklet';
495
525
  const { translation } = eventData;
@@ -596,7 +626,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
596
626
  return;
597
627
  }
598
628
  const { isBoundary, resetOffset } = reachBoundary(eventData);
599
- if (isBoundary && circularShared.value) {
629
+ if (childrenLength.value > 1 && isBoundary && circularShared.value) {
600
630
  offset.value = resetOffset;
601
631
  }
602
632
  else {
@@ -614,6 +644,9 @@ const SwiperWrapper = forwardRef((props, ref) => {
614
644
  const eventData = {
615
645
  translation: moveDistance
616
646
  };
647
+ if (childrenLength.value === 1) {
648
+ return handleBackInit();
649
+ }
617
650
  // 用户手指按下起来, 需要计算正确的位置, 比如在滑动过程中突然按下然后起来,需要计算到正确的位置
618
651
  if (!circularShared.value && !canMove(eventData)) {
619
652
  return;
@@ -625,11 +658,26 @@ const SwiperWrapper = forwardRef((props, ref) => {
625
658
  else {
626
659
  handleEnd(eventData);
627
660
  }
628
- });
661
+ })
662
+ .withRef(swiperGestureRef);
663
+ // swiper横向,当y轴滑动5像素手势失效;swiper纵向只响应swiper的滑动事件
664
+ if (dir === 'x') {
665
+ gesturePan.activeOffsetX([-2, 2]).failOffsetY([-5, 5]);
666
+ }
667
+ else {
668
+ gesturePan.activeOffsetY([-2, 2]).failOffsetX([-5, 5]);
669
+ }
670
+ // 手势协同2.0
671
+ if (simultaneousHandlers && simultaneousHandlers.length) {
672
+ gesturePan.simultaneousWithExternalGesture(...simultaneousHandlers);
673
+ }
674
+ if (waitForHandlers && waitForHandlers.length) {
675
+ gesturePan.requireExternalGestureToFail(...waitForHandlers);
676
+ }
629
677
  return {
630
678
  gestureHandler: gesturePan
631
679
  };
632
- }, []);
680
+ }, [gestureSwitch.current]);
633
681
  const animatedStyles = useAnimatedStyle(() => {
634
682
  if (dir === 'x') {
635
683
  return { transform: [{ translateX: offset.value }], opacity: step.value > 0 ? 1 : 0 };
@@ -638,34 +686,32 @@ const SwiperWrapper = forwardRef((props, ref) => {
638
686
  return { transform: [{ translateY: offset.value }], opacity: step.value > 0 ? 1 : 0 };
639
687
  }
640
688
  });
641
- function renderSwiper() {
642
- const arrPages = renderItems();
643
- return (<View style={[normalStyle, layoutStyle, styles.swiper]} {...layoutProps} {...innerProps}>
644
- <Animated.View style={[{
645
- flexDirection: dir === 'x' ? 'row' : 'column',
646
- width: '100%',
647
- height: '100%'
648
- }, animatedStyles]}>
649
- {wrapChildren({
650
- children: arrPages
651
- }, {
652
- hasVarDec,
653
- varContext: varContextRef.current,
654
- textStyle,
655
- textProps
656
- })}
657
- </Animated.View>
658
- {showsPagination && renderPagination()}
659
- </View>);
660
- }
661
- if (children.length === 1) {
662
- return renderSwiper();
689
+ let finalComponent;
690
+ const arrPages = renderItems();
691
+ const mergeProps = Object.assign({
692
+ style: [normalStyle, layoutStyle, styles.swiper]
693
+ }, layoutProps, innerProps);
694
+ const animateComponent = createElement(Animated.View, {
695
+ style: [{ flexDirection: dir === 'x' ? 'row' : 'column', width: '100%', height: '100%' }, animatedStyles]
696
+ }, wrapChildren({
697
+ children: arrPages
698
+ }, {
699
+ hasVarDec,
700
+ varContext: varContextRef.current,
701
+ textStyle,
702
+ textProps
703
+ }));
704
+ const renderChildrens = showPagination ? [animateComponent, renderPagination()] : animateComponent;
705
+ finalComponent = createElement(View, mergeProps, renderChildrens);
706
+ if (!disableGesture) {
707
+ finalComponent = createElement(GestureDetector, {
708
+ gesture: gestureHandler
709
+ }, finalComponent);
663
710
  }
664
- else {
665
- return (<GestureDetector gesture={gestureHandler}>
666
- {renderSwiper()}
667
- </GestureDetector>);
711
+ if (hasPositionFixed) {
712
+ finalComponent = createElement(Portal, null, finalComponent);
668
713
  }
714
+ return finalComponent;
669
715
  });
670
716
  SwiperWrapper.displayName = 'MpxSwiperWrapper';
671
717
  export default SwiperWrapper;
@@ -10,6 +10,7 @@ import { warn } from '@mpxjs/utils';
10
10
  import useNodesRef from './useNodesRef'; // 引入辅助函数
11
11
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
12
12
  import CheckBox from './mpx-checkbox';
13
+ import Portal from './mpx-portal';
13
14
  import { FormContext } from './context';
14
15
  import { useTransformStyle, useLayout, extendObject } from './utils';
15
16
  const _Switch = forwardRef((props, ref) => {
@@ -21,7 +22,7 @@ const _Switch = forwardRef((props, ref) => {
21
22
  if (formContext) {
22
23
  formValuesMap = formContext.formValuesMap;
23
24
  }
24
- const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, {
25
+ const { normalStyle, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(style, {
25
26
  enableVar,
26
27
  externalVarContext,
27
28
  parentFontSize,
@@ -83,13 +84,17 @@ const _Switch = forwardRef((props, ref) => {
83
84
  checked: isChecked
84
85
  }));
85
86
  }
86
- return createElement(Switch, extendObject({}, innerProps, {
87
+ let finalComponent = createElement(Switch, extendObject({}, innerProps, {
87
88
  style: normalStyle,
88
89
  value: isChecked,
89
90
  trackColor: { false: '#FFF', true: color },
90
91
  thumbColor: isChecked ? '#FFF' : '#f4f3f4',
91
92
  ios_backgroundColor: '#FFF'
92
93
  }));
94
+ if (hasPositionFixed) {
95
+ finalComponent = createElement(Portal, null, finalComponent);
96
+ }
97
+ return finalComponent;
93
98
  });
94
99
  _Switch.displayName = 'MpxSwitch';
95
100
  export default _Switch;
@@ -5,12 +5,13 @@
5
5
  */
6
6
  import { Text } from 'react-native';
7
7
  import { useRef, forwardRef, createElement } from 'react';
8
+ import Portal from './mpx-portal';
8
9
  import useInnerProps from './getInnerListeners';
9
10
  import useNodesRef from './useNodesRef'; // 引入辅助函数
10
11
  import { useTransformStyle, wrapChildren, extendObject } from './utils';
11
12
  const _Text = forwardRef((props, ref) => {
12
13
  const { style = {}, allowFontScaling = false, selectable, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'user-select': userSelect, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
13
- const { normalStyle, hasVarDec, varContextRef } = useTransformStyle(style, {
14
+ const { normalStyle, hasVarDec, varContextRef, hasPositionFixed } = useTransformStyle(style, {
14
15
  enableVar,
15
16
  externalVarContext,
16
17
  parentFontSize,
@@ -29,10 +30,14 @@ const _Text = forwardRef((props, ref) => {
29
30
  }), [
30
31
  'user-select'
31
32
  ]);
32
- return createElement(Text, innerProps, wrapChildren(props, {
33
+ let finalComponent = createElement(Text, innerProps, wrapChildren(props, {
33
34
  hasVarDec,
34
35
  varContext: varContextRef.current
35
36
  }));
37
+ if (hasPositionFixed) {
38
+ finalComponent = createElement(Portal, null, finalComponent);
39
+ }
40
+ return finalComponent;
36
41
  });
37
42
  _Text.displayName = 'MpxText';
38
43
  export default _Text;
@@ -68,6 +68,7 @@ import { StyleSheet, View } from 'react-native';
68
68
  import { splitProps, useTransformStyle, useLayout, extendObject } from './utils';
69
69
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
70
70
  import useNodesRef from './useNodesRef';
71
+ import Portal from './mpx-portal';
71
72
  const styles = StyleSheet.create({
72
73
  container: {
73
74
  width: 300,
@@ -85,7 +86,7 @@ const MpxVideo = forwardRef((videoProps, ref) => {
85
86
  const videoInfoRef = useRef({});
86
87
  const propsRef = useRef({});
87
88
  propsRef.current = props;
88
- const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(extendObject({}, styles.container, style), {
89
+ const { normalStyle, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(extendObject({}, styles.container, style), {
89
90
  enableVar,
90
91
  externalVarContext,
91
92
  parentFontSize,
@@ -243,6 +244,10 @@ const MpxVideo = forwardRef((videoProps, ref) => {
243
244
  'bindcontrolstoggle',
244
245
  'bindseekcomplete'
245
246
  ], { layoutRef });
246
- return createElement(View, { style: extendObject({}, normalStyle, layoutStyle), ref: viewRef }, createElement(Video, innerProps));
247
+ let videoComponent = createElement(View, { style: extendObject({}, normalStyle, layoutStyle), ref: viewRef }, createElement(Video, innerProps));
248
+ if (hasPositionFixed) {
249
+ videoComponent = createElement(Portal, null, videoComponent);
250
+ }
251
+ return videoComponent;
247
252
  });
248
253
  export default MpxVideo;
@@ -11,7 +11,7 @@ import Animated from 'react-native-reanimated';
11
11
  import useAnimationHooks from './useAnimationHooks';
12
12
  import useNodesRef from './useNodesRef';
13
13
  import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage, pickStyle, extendObject, useHover } from './utils';
14
- import { error } from '@mpxjs/utils';
14
+ import { error, isFunction } from '@mpxjs/utils';
15
15
  import LinearGradient from 'react-native-linear-gradient';
16
16
  import { GestureDetector } from 'react-native-gesture-handler';
17
17
  import Portal from './mpx-portal';
@@ -523,10 +523,8 @@ function useWrapImage(imageStyle, innerStyle, enableFastImage) {
523
523
  setShow(true);
524
524
  }
525
525
  };
526
- return <View key='backgroundImage' {...needLayout ? { onLayout } : null} style={{ ...inheritStyle(innerStyle), ...StyleSheet.absoluteFillObject, overflow: 'hidden' }}>
527
- {show && type === 'linear' && <LinearGradient useAngle={true} {...imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current)}/>}
528
- {show && type === 'image' && (renderImage(imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current), enableFastImage))}
529
- </View>;
526
+ const backgroundProps = extendObject({ key: 'backgroundImage' }, needLayout ? { onLayout } : {}, { style: extendObject({}, inheritStyle(innerStyle), StyleSheet.absoluteFillObject, { overflow: 'hidden' }) });
527
+ return createElement(View, backgroundProps, show && type === 'linear' && createElement(LinearGradient, extendObject({ useAngle: true }, imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current))), show && type === 'image' && renderImage(imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current), enableFastImage));
530
528
  }
531
529
  function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps, innerStyle, enableFastImage }) {
532
530
  const children = wrapChildren(props, {
@@ -543,7 +541,7 @@ function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backg
543
541
  }
544
542
  const _View = forwardRef((viewProps, ref) => {
545
543
  const { textProps, innerProps: props = {} } = splitProps(viewProps);
546
- let { style = {}, 'hover-style': hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'enable-background': enableBackground, 'enable-fast-image': enableFastImage, 'enable-animation': enableAnimation, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, animation } = props;
544
+ let { style = {}, 'hover-style': hoverStyle, 'hover-start-time': hoverStartTime = 50, 'hover-stay-time': hoverStayTime = 400, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'enable-background': enableBackground, 'enable-fast-image': enableFastImage, 'enable-animation': enableAnimation, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, animation, catchtransitionend, bindtransitionend } = props;
547
545
  // 默认样式
548
546
  const defaultStyle = style.display === 'flex'
549
547
  ? {
@@ -575,10 +573,17 @@ const _View = forwardRef((viewProps, ref) => {
575
573
  });
576
574
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
577
575
  const viewStyle = extendObject({}, innerStyle, layoutStyle);
576
+ const transitionend = isFunction(catchtransitionend)
577
+ ? catchtransitionend
578
+ : isFunction(bindtransitionend)
579
+ ? bindtransitionend
580
+ : undefined;
578
581
  const { enableStyleAnimation, animationStyle } = useAnimationHooks({
579
- enableAnimation,
582
+ layoutRef,
580
583
  animation,
581
- style: viewStyle
584
+ enableAnimation,
585
+ style: viewStyle,
586
+ transitionend
582
587
  });
583
588
  const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
584
589
  ref: nodeRef,
@@ -1,6 +1,6 @@
1
1
  import { useEffect, useMemo, useRef } from 'react';
2
- import { Easing, useSharedValue, withTiming, useAnimatedStyle, withSequence, withDelay, makeMutable, cancelAnimation } from 'react-native-reanimated';
3
- import { error, hasOwn } from '@mpxjs/utils';
2
+ import { Easing, useSharedValue, withTiming, useAnimatedStyle, withSequence, withDelay, makeMutable, cancelAnimation, runOnJS } from 'react-native-reanimated';
3
+ import { error, hasOwn, collectDataset } from '@mpxjs/utils';
4
4
  // 微信 timingFunction 和 RN Easing 对应关系
5
5
  const EasingKey = {
6
6
  linear: Easing.linear,
@@ -140,7 +140,7 @@ function getTransformObj(transforms) {
140
140
  }, {});
141
141
  }
142
142
  export default function useAnimationHooks(props) {
143
- const { style = {}, animation, enableAnimation } = props;
143
+ const { style = {}, animation, enableAnimation, transitionend, layoutRef } = props;
144
144
  const enableStyleAnimation = enableAnimation || !!animation;
145
145
  const enableAnimationRef = useRef(enableStyleAnimation);
146
146
  if (enableAnimationRef.current !== enableStyleAnimation) {
@@ -249,10 +249,33 @@ export default function useAnimationHooks(props) {
249
249
  });
250
250
  });
251
251
  }
252
+ function withTimingCallback(finished, current, duration) {
253
+ if (!transitionend)
254
+ return;
255
+ const target = {
256
+ id: animation?.id || -1,
257
+ dataset: collectDataset(props),
258
+ offsetLeft: layoutRef?.current?.offsetLeft || 0,
259
+ offsetTop: layoutRef?.current?.offsetTop || 0
260
+ };
261
+ transitionend({
262
+ type: 'transitionend',
263
+ // elapsedTime 对齐wx 单位s
264
+ detail: { elapsedTime: duration ? duration / 1000 : 0, finished, current },
265
+ target,
266
+ currentTarget: target,
267
+ timeStamp: Date.now()
268
+ });
269
+ }
252
270
  // 创建单个animation
253
271
  function getAnimation({ key, value }, { delay, duration, easing }, callback) {
254
272
  const animation = typeof callback === 'function'
255
- ? withTiming(value, { duration, easing }, callback)
273
+ ? withTiming(value, { duration, easing }, (finished, current) => {
274
+ callback(finished, current);
275
+ if (transitionend && finished) {
276
+ runOnJS(withTimingCallback)(finished, current, duration);
277
+ }
278
+ })
256
279
  : withTiming(value, { duration, easing });
257
280
  return delay ? withDelay(delay, animation) : animation;
258
281
  }
@@ -1,4 +1,4 @@
1
- import { useEffect, useCallback, useMemo, useRef, isValidElement, useContext, useState, Children, cloneElement } from 'react';
1
+ import { useEffect, useCallback, useMemo, useRef, isValidElement, useContext, useState, Children, cloneElement, createElement } from 'react';
2
2
  import { Image } from 'react-native';
3
3
  import { isObject, isFunction, isNumber, hasOwn, diffAndCloneA, error, warn } from '@mpxjs/utils';
4
4
  import { VarContext, ScrollViewContext, RouteContext } from './context';
@@ -26,6 +26,7 @@ const unoVarDecRegExp = /^--un-/;
26
26
  const unoVarUseRegExp = /var\(--un-/;
27
27
  const calcUseRegExp = /calc\(/;
28
28
  const envUseRegExp = /env\(/;
29
+ const filterRegExp = /(calc|env|%)/;
29
30
  const safeAreaInsetMap = {
30
31
  'safe-area-inset-top': 'top',
31
32
  'safe-area-inset-right': 'right',
@@ -181,10 +182,11 @@ function resolveVar(input, varContext) {
181
182
  });
182
183
  return global.__formatValue(replaced.source());
183
184
  }
184
- function transformVar(styleObj, varKeyPaths, varContext) {
185
+ function transformVar(styleObj, varKeyPaths, varContext, visitOther) {
185
186
  varKeyPaths.forEach((varKeyPath) => {
186
187
  setStyle(styleObj, varKeyPath, ({ target, key, value }) => {
187
188
  target[key] = resolveVar(value, varContext);
189
+ visitOther({ target, key, value: target[key], keyPath: varKeyPath });
188
190
  });
189
191
  });
190
192
  }
@@ -224,28 +226,33 @@ function transformCalc(styleObj, calcKeyPaths, formatter) {
224
226
  });
225
227
  });
226
228
  }
227
- const stringifyProps = ['fontWeight'];
228
229
  function transformStringify(styleObj) {
229
- stringifyProps.forEach((prop) => {
230
- if (isNumber(styleObj[prop])) {
231
- styleObj[prop] = '' + styleObj[prop];
232
- }
233
- });
230
+ if (isNumber(styleObj.fontWeight)) {
231
+ styleObj.fontWeight = '' + styleObj.fontWeight;
232
+ }
233
+ }
234
+ function transformPosition(styleObj, meta) {
235
+ if (styleObj.position === 'fixed') {
236
+ styleObj.position = 'absolute';
237
+ meta.hasPositionFixed = true;
238
+ }
234
239
  }
235
240
  export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }) {
236
241
  const varStyle = {};
237
242
  const unoVarStyle = {};
238
243
  const normalStyle = {};
239
- const normalStyleRef = useRef({});
240
- const normalStyleChangedRef = useRef(false);
241
244
  let hasVarDec = false;
242
245
  let hasVarUse = false;
246
+ let hasSelfPercent = false;
243
247
  const varKeyPaths = [];
244
248
  const unoVarKeyPaths = [];
249
+ const percentKeyPaths = [];
250
+ const calcKeyPaths = [];
251
+ const envKeyPaths = [];
245
252
  const [width, setWidth] = useState(0);
246
253
  const [height, setHeight] = useState(0);
247
254
  const navigation = useNavigation();
248
- function varVisitor({ key, value, keyPath }) {
255
+ function varVisitor({ target, key, value, keyPath }) {
249
256
  if (keyPath.length === 1) {
250
257
  if (unoVarDecRegExp.test(key)) {
251
258
  unoVarStyle[key] = value;
@@ -269,6 +276,33 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
269
276
  hasVarUse = true;
270
277
  varKeyPaths.push(keyPath.slice());
271
278
  }
279
+ else {
280
+ visitOther({ target, key, value, keyPath });
281
+ }
282
+ }
283
+ }
284
+ function envVisitor({ value, keyPath }) {
285
+ if (envUseRegExp.test(value)) {
286
+ envKeyPaths.push(keyPath.slice());
287
+ }
288
+ }
289
+ function calcVisitor({ value, keyPath }) {
290
+ if (calcUseRegExp.test(value)) {
291
+ calcKeyPaths.push(keyPath.slice());
292
+ }
293
+ }
294
+ function percentVisitor({ key, value, keyPath }) {
295
+ if (hasOwn(selfPercentRule, key) && PERCENT_REGEX.test(value)) {
296
+ hasSelfPercent = true;
297
+ percentKeyPaths.push(keyPath.slice());
298
+ }
299
+ else if ((key === 'fontSize' || key === 'lineHeight') && PERCENT_REGEX.test(value)) {
300
+ percentKeyPaths.push(keyPath.slice());
301
+ }
302
+ }
303
+ function visitOther({ target, key, value, keyPath }) {
304
+ if (filterRegExp.test(value)) {
305
+ [envVisitor, percentVisitor, calcVisitor].forEach(visitor => visitor({ target, key, value, keyPath }));
272
306
  }
273
307
  }
274
308
  // traverse var & generate normalStyle
@@ -289,96 +323,57 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
289
323
  if (diffAndCloneA(varContextRef.current, newVarContext).diff) {
290
324
  varContextRef.current = newVarContext;
291
325
  }
292
- transformVar(normalStyle, varKeyPaths, varContextRef.current);
326
+ transformVar(normalStyle, varKeyPaths, varContextRef.current, visitOther);
293
327
  }
294
328
  // apply unocss var
295
329
  if (unoVarKeyPaths.length) {
296
- transformVar(normalStyle, unoVarKeyPaths, unoVarStyle);
297
- }
298
- const { clone, diff } = diffAndCloneA(normalStyle, normalStyleRef.current);
299
- if (diff) {
300
- normalStyleRef.current = clone;
301
- normalStyleChangedRef.current = !normalStyleChangedRef.current;
330
+ transformVar(normalStyle, unoVarKeyPaths, unoVarStyle, visitOther);
302
331
  }
303
- const memoResult = useMemo(() => {
304
- let hasSelfPercent = false;
305
- let hasPositionFixed = false;
306
- const percentKeyPaths = [];
307
- const calcKeyPaths = [];
308
- const envKeyPaths = [];
309
- // transform can be memoized
310
- function envVisitor({ value, keyPath }) {
311
- if (envUseRegExp.test(value)) {
312
- envKeyPaths.push(keyPath.slice());
313
- }
314
- }
315
- function calcVisitor({ value, keyPath }) {
316
- if (calcUseRegExp.test(value)) {
317
- calcKeyPaths.push(keyPath.slice());
318
- }
319
- }
320
- function percentVisitor({ key, value, keyPath }) {
321
- if (hasOwn(selfPercentRule, key) && PERCENT_REGEX.test(value)) {
322
- hasSelfPercent = true;
323
- percentKeyPaths.push(keyPath.slice());
324
- }
325
- else if ((key === 'fontSize' || key === 'lineHeight') && PERCENT_REGEX.test(value)) {
326
- percentKeyPaths.push(keyPath.slice());
327
- }
328
- }
329
- function transformPosition(styleObj) {
330
- if (styleObj.position === 'fixed') {
331
- hasPositionFixed = true;
332
- styleObj.position = 'absolute';
333
- }
332
+ const percentConfig = {
333
+ width,
334
+ height,
335
+ fontSize: normalStyle.fontSize,
336
+ parentWidth,
337
+ parentHeight,
338
+ parentFontSize
339
+ };
340
+ const positionMeta = {
341
+ hasPositionFixed: false
342
+ };
343
+ // apply env
344
+ transformEnv(normalStyle, envKeyPaths, navigation);
345
+ // apply percent
346
+ transformPercent(normalStyle, percentKeyPaths, percentConfig);
347
+ // apply calc
348
+ transformCalc(normalStyle, calcKeyPaths, (value, key) => {
349
+ if (PERCENT_REGEX.test(value)) {
350
+ const resolved = resolvePercent(value, key, percentConfig);
351
+ return typeof resolved === 'number' ? resolved : 0;
334
352
  }
335
- // traverse env & calc & percent
336
- traverseStyle(normalStyle, [envVisitor, percentVisitor, calcVisitor]);
337
- const percentConfig = {
338
- width,
339
- height,
340
- fontSize: normalStyle.fontSize,
341
- parentWidth,
342
- parentHeight,
343
- parentFontSize
344
- };
345
- // apply env
346
- transformEnv(normalStyle, envKeyPaths, navigation);
347
- // apply percent
348
- transformPercent(normalStyle, percentKeyPaths, percentConfig);
349
- // apply calc
350
- transformCalc(normalStyle, calcKeyPaths, (value, key) => {
351
- if (PERCENT_REGEX.test(value)) {
352
- const resolved = resolvePercent(value, key, percentConfig);
353
- return typeof resolved === 'number' ? resolved : 0;
353
+ else {
354
+ const formatted = global.__formatValue(value);
355
+ if (typeof formatted === 'number') {
356
+ return formatted;
354
357
  }
355
358
  else {
356
- const formatted = global.__formatValue(value);
357
- if (typeof formatted === 'number') {
358
- return formatted;
359
- }
360
- else {
361
- warn('calc() only support number, px, rpx, % temporarily.');
362
- return 0;
363
- }
359
+ warn('calc() only support number, px, rpx, % temporarily.');
360
+ return 0;
364
361
  }
365
- });
366
- // apply position
367
- transformPosition(normalStyle);
368
- // transform number enum stringify
369
- transformStringify(normalStyle);
370
- return {
371
- normalStyle,
372
- hasSelfPercent,
373
- hasPositionFixed
374
- };
375
- }, [normalStyleChangedRef.current, width, height, parentWidth, parentHeight, parentFontSize]);
376
- return extendObject({
362
+ }
363
+ });
364
+ // apply position
365
+ transformPosition(normalStyle, positionMeta);
366
+ // transform number enum stringify
367
+ transformStringify(normalStyle);
368
+ return {
377
369
  hasVarDec,
378
370
  varContextRef,
379
371
  setWidth,
380
- setHeight
381
- }, memoResult);
372
+ setHeight,
373
+ normalStyle,
374
+ hasSelfPercent,
375
+ hasPositionFixed: positionMeta.hasPositionFixed
376
+ };
382
377
  }
383
378
  export function traverseStyle(styleObj, visitors) {
384
379
  const keyPath = [];
@@ -387,12 +382,7 @@ export function traverseStyle(styleObj, visitors) {
387
382
  target.forEach((value, index) => {
388
383
  const key = String(index);
389
384
  keyPath.push(key);
390
- visitors.forEach(visitor => visitor({
391
- target,
392
- key,
393
- value,
394
- keyPath
395
- }));
385
+ visitors.forEach(visitor => visitor({ target, key, value, keyPath }));
396
386
  traverse(value);
397
387
  keyPath.pop();
398
388
  });
@@ -538,7 +528,7 @@ export function getCurrentPage(pageId) {
538
528
  }
539
529
  export function renderImage(imageProps, enableFastImage = false) {
540
530
  const Component = enableFastImage ? FastImage : Image;
541
- return <Component {...imageProps}/>;
531
+ return createElement(Component, imageProps);
542
532
  }
543
533
  export function pickStyle(styleObj = {}, pickedKeys, callback) {
544
534
  return pickedKeys.reduce((acc, key) => {