@mpxjs/webpack-plugin 2.9.69-beta.5 → 2.9.69-beta.7

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.
@@ -10,7 +10,7 @@ import useInnerProps from './getInnerListeners';
10
10
  import Animated from 'react-native-reanimated';
11
11
  import useAnimationHooks from './useAnimationHooks';
12
12
  import useNodesRef from './useNodesRef';
13
- import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage, pickStyle, extendObject, useHoverStyle } from './utils';
13
+ import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage, pickStyle, extendObject, useHover } from './utils';
14
14
  import { error } from '@mpxjs/utils';
15
15
  import LinearGradient from 'react-native-linear-gradient';
16
16
  import { GestureDetector } from 'react-native-gesture-handler';
@@ -442,7 +442,7 @@ function inheritStyle(innerStyle = {}) {
442
442
  }
443
443
  : undefined);
444
444
  }
445
- function wrapImage(imageStyle, innerStyle, enableFastImage) {
445
+ function useWrapImage(imageStyle, innerStyle, enableFastImage) {
446
446
  // 预处理数据
447
447
  const preImageInfo = preParseImage(imageStyle);
448
448
  // 预解析
@@ -528,11 +528,6 @@ function wrapImage(imageStyle, innerStyle, enableFastImage) {
528
528
  </View>;
529
529
  }
530
530
  function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps, innerStyle, enableFastImage }) {
531
- enableBackground = enableBackground || !!backgroundStyle;
532
- const enableBackgroundRef = useRef(enableBackground);
533
- if (enableBackgroundRef.current !== enableBackground) {
534
- error('[Mpx runtime error]: background use should be stable in the component lifecycle, or you can set [enable-background] with true.');
535
- }
536
531
  const children = wrapChildren(props, {
537
532
  hasVarDec,
538
533
  varContext,
@@ -540,13 +535,14 @@ function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backg
540
535
  textProps
541
536
  });
542
537
  return [
543
- enableBackground ? wrapImage(backgroundStyle, innerStyle, enableFastImage) : null,
538
+ // eslint-disable-next-line react-hooks/rules-of-hooks
539
+ enableBackground ? useWrapImage(backgroundStyle, innerStyle, enableFastImage) : null,
544
540
  children
545
541
  ];
546
542
  }
547
543
  const _View = forwardRef((viewProps, ref) => {
548
544
  const { textProps, innerProps: props = {} } = splitProps(viewProps);
549
- const { 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;
545
+ 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;
550
546
  // 默认样式
551
547
  const defaultStyle = style.display === 'flex'
552
548
  ? {
@@ -556,7 +552,8 @@ const _View = forwardRef((viewProps, ref) => {
556
552
  flexWrap: 'nowrap'
557
553
  }
558
554
  : {};
559
- const { isHover, enableHoverStyle, gesture } = useHoverStyle({ hoverStyle, hoverStartTime, hoverStayTime });
555
+ const enableHover = !!hoverStyle;
556
+ const { isHover, gesture } = useHover({ enableHover, hoverStartTime, hoverStayTime });
560
557
  const styleObj = extendObject({}, defaultStyle, style, isHover ? hoverStyle : {});
561
558
  const { normalStyle, hasSelfPercent, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, {
562
559
  enableVar,
@@ -566,6 +563,11 @@ const _View = forwardRef((viewProps, ref) => {
566
563
  parentHeight
567
564
  });
568
565
  const { textStyle, backgroundStyle, innerStyle = {} } = splitStyle(normalStyle);
566
+ enableBackground = enableBackground || !!backgroundStyle;
567
+ const enableBackgroundRef = useRef(enableBackground);
568
+ if (enableBackgroundRef.current !== enableBackground) {
569
+ error('[Mpx runtime error]: background use should be stable in the component lifecycle, or you can set [enable-background] with true.');
570
+ }
569
571
  const nodeRef = useRef(null);
570
572
  useNodesRef(props, ref, nodeRef, {
571
573
  style: normalStyle
@@ -590,7 +592,7 @@ const _View = forwardRef((viewProps, ref) => {
590
592
  });
591
593
  const childNode = wrapWithChildren(props, {
592
594
  hasVarDec,
593
- enableBackground,
595
+ enableBackground: enableBackgroundRef.current,
594
596
  textStyle,
595
597
  backgroundStyle,
596
598
  varContext: varContextRef.current,
@@ -601,8 +603,8 @@ const _View = forwardRef((viewProps, ref) => {
601
603
  const BaseComponent = enableStyleAnimation
602
604
  ? createElement(Animated.View, innerProps, childNode)
603
605
  : createElement(View, innerProps, childNode);
604
- return enableHoverStyle
605
- ? createElement(GestureDetector, { gesture }, BaseComponent)
606
+ return enableHover
607
+ ? createElement(GestureDetector, { gesture: gesture }, BaseComponent)
606
608
  : BaseComponent;
607
609
  });
608
610
  _View.displayName = 'MpxView';
@@ -1,13 +1,14 @@
1
1
  import { forwardRef, useRef, useContext, useMemo, useState, useCallback, useEffect } from 'react';
2
- import { warn, getFocusedNavigation, isFunction } from '@mpxjs/utils';
2
+ import { warn, isFunction } from '@mpxjs/utils';
3
3
  import Portal from './mpx-portal';
4
4
  import { getCustomEvent } from './getInnerListeners';
5
5
  import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab } from '@mpxjs/api-proxy';
6
6
  import { WebView } from 'react-native-webview';
7
7
  import useNodesRef from './useNodesRef';
8
- import { getCurrentPage, extendObject } from './utils';
8
+ import { getCurrentPage } from './utils';
9
+ import { useNavigation } from '@react-navigation/native';
9
10
  import { RouteContext } from './context';
10
- import { BackHandler, StyleSheet, View, Text, Platform } from 'react-native';
11
+ import { BackHandler, StyleSheet, View, Text } from 'react-native';
11
12
  const styles = StyleSheet.create({
12
13
  loadErrorContext: {
13
14
  display: 'flex',
@@ -53,6 +54,7 @@ const _WebView = forwardRef((props, ref) => {
53
54
  const [pageLoadErr, setPageLoadErr] = useState(false);
54
55
  const currentPage = useMemo(() => getCurrentPage(pageId), [pageId]);
55
56
  const webViewRef = useRef(null);
57
+ const isLoaded = useRef(false);
56
58
  const defaultWebViewStyle = {
57
59
  position: 'absolute',
58
60
  left: 0,
@@ -61,6 +63,7 @@ const _WebView = forwardRef((props, ref) => {
61
63
  bottom: 0
62
64
  };
63
65
  const canGoBack = useRef(false);
66
+ const isNavigateBack = useRef(false);
64
67
  const onAndroidBackPress = useCallback(() => {
65
68
  if (canGoBack.current) {
66
69
  webViewRef.current?.goBack();
@@ -69,42 +72,27 @@ const _WebView = forwardRef((props, ref) => {
69
72
  return false;
70
73
  }, [canGoBack]);
71
74
  const beforeRemoveHandle = useCallback((e) => {
72
- if (canGoBack.current) {
75
+ if (canGoBack.current && !isNavigateBack.current) {
73
76
  webViewRef.current?.goBack();
74
77
  e.preventDefault();
75
78
  }
79
+ isNavigateBack.current = false;
76
80
  }, [canGoBack]);
77
- const navigation = getFocusedNavigation();
78
- // ios 16以下版本 的hash会被转义,因此对于iOS环境下在页面load之后再注入hash部分的逻辑
79
- let [baseUrl, hashParams = ''] = src.split('#');
80
- if (hashParams)
81
- hashParams = '#' + hashParams;
82
- const source = useMemo(() => {
83
- if (Platform.OS === 'ios') {
84
- return { uri: baseUrl };
85
- }
86
- return { uri: baseUrl + hashParams };
87
- }, [baseUrl, hashParams]);
88
- const hashInjectedJavascript = useMemo(() => {
89
- if (Platform.OS === 'ios' && hashParams) {
90
- return `(function() {
91
- try {
92
- location.hash = '${hashParams}';
93
- } catch(e) {
94
- }
95
- })()`;
96
- }
97
- return '';
98
- }, [hashParams]);
99
- navigation?.addListener('beforeRemove', beforeRemoveHandle);
81
+ const navigation = useNavigation();
100
82
  useEffect(() => {
101
83
  if (__mpx_mode__ === 'android') {
102
84
  BackHandler.addEventListener('hardwareBackPress', onAndroidBackPress);
103
- return () => {
104
- BackHandler.removeEventListener('hardwareBackPress', onAndroidBackPress);
105
- navigation?.removeListener('beforeRemove', beforeRemoveHandle);
106
- };
107
85
  }
86
+ const addListener = navigation?.addListener.bind(navigation);
87
+ const beforeRemoveSubscription = addListener?.('beforeRemove', beforeRemoveHandle);
88
+ return () => {
89
+ if (__mpx_mode__ === 'android') {
90
+ BackHandler.removeEventListener('hardwareBackPress', onAndroidBackPress);
91
+ }
92
+ if (isFunction(beforeRemoveSubscription)) {
93
+ beforeRemoveSubscription();
94
+ }
95
+ };
108
96
  }, []);
109
97
  useNodesRef(props, ref, webViewRef, {
110
98
  style: defaultWebViewStyle
@@ -112,27 +100,6 @@ const _WebView = forwardRef((props, ref) => {
112
100
  if (!src) {
113
101
  return null;
114
102
  }
115
- const _load = function (res) {
116
- const result = {
117
- type: 'load',
118
- timeStamp: res.timeStamp,
119
- detail: {
120
- src: res.nativeEvent?.url
121
- }
122
- };
123
- bindload?.(result);
124
- };
125
- const _error = function (res) {
126
- setPageLoadErr(true);
127
- const result = {
128
- type: 'error',
129
- timeStamp: res.timeStamp,
130
- detail: {
131
- src: ''
132
- }
133
- };
134
- binderror && binderror(result);
135
- };
136
103
  const _reload = function () {
137
104
  setPageLoadErr(false);
138
105
  };
@@ -159,7 +126,6 @@ const _WebView = forwardRef((props, ref) => {
159
126
  return _documentTitle
160
127
  }
161
128
  });
162
- ${hashInjectedJavascript}
163
129
  }
164
130
  true;
165
131
  `;
@@ -218,6 +184,7 @@ const _WebView = forwardRef((props, ref) => {
218
184
  asyncCallback = navObj.navigateTo(...params);
219
185
  break;
220
186
  case 'navigateBack':
187
+ isNavigateBack.current = true;
221
188
  asyncCallback = navObj.navigateBack(...params);
222
189
  break;
223
190
  case 'redirectTo':
@@ -264,22 +231,58 @@ const _WebView = forwardRef((props, ref) => {
264
231
  }
265
232
  });
266
233
  };
267
- const events = {};
268
- if (bindload) {
269
- extendObject(events, {
270
- onLoad: _load
271
- });
272
- }
273
- extendObject(events, {
274
- onError: _error
275
- });
234
+ let isLoadError = false;
235
+ let fristLoaded = false;
236
+ let statusCode = '';
237
+ const onLoadEnd = function (res) {
238
+ fristLoaded = true;
239
+ isLoaded.current = true;
240
+ const src = res.nativeEvent?.url;
241
+ if (isLoadError) {
242
+ isLoadError = false;
243
+ isNavigateBack.current = false;
244
+ const result = {
245
+ type: 'error',
246
+ timeStamp: res.timeStamp,
247
+ detail: {
248
+ src,
249
+ statusCode
250
+ }
251
+ };
252
+ binderror && binderror(result);
253
+ }
254
+ else {
255
+ const result = {
256
+ type: 'load',
257
+ timeStamp: res.timeStamp,
258
+ detail: {
259
+ src
260
+ }
261
+ };
262
+ bindload?.(result);
263
+ }
264
+ };
265
+ const onHttpError = function (res) {
266
+ isLoadError = true;
267
+ statusCode = res.nativeEvent?.statusCode;
268
+ };
269
+ const onError = function () {
270
+ statusCode = '';
271
+ isLoadError = true;
272
+ if (!fristLoaded) {
273
+ setPageLoadErr(true);
274
+ }
275
+ };
276
+ const onLoadStart = function () {
277
+ isLoaded.current = false;
278
+ };
276
279
  return (<Portal key={pageLoadErr ? 'error' : 'webview'}>
277
280
  {pageLoadErr
278
281
  ? (<View style={[styles.loadErrorContext, defaultWebViewStyle]}>
279
282
  <View style={styles.loadErrorText}><Text style={{ fontSize: 14, color: '#999999' }}>{currentErrorText.text}</Text></View>
280
283
  <View style={styles.loadErrorButton} onTouchEnd={_reload}><Text style={{ fontSize: 12, color: '#666666' }}>{currentErrorText.button}</Text></View>
281
284
  </View>)
282
- : (<WebView style={defaultWebViewStyle} source={source} ref={webViewRef} javaScriptEnabled={true} onNavigationStateChange={_changeUrl} onMessage={_message} injectedJavaScript={injectedJavaScript} onLoadProgress={_onLoadProgress} allowsBackForwardNavigationGestures={true} {...events}></WebView>)}
285
+ : (<WebView style={defaultWebViewStyle} source={{ uri: src }} pointerEvents={isLoaded ? 'auto' : 'none'} ref={webViewRef} javaScriptEnabled={true} onNavigationStateChange={_changeUrl} onMessage={_message} injectedJavaScript={injectedJavaScript} onLoadProgress={_onLoadProgress} onLoadEnd={onLoadEnd} onHttpError={onHttpError} onError={onError} onLoadStart={onLoadStart} allowsBackForwardNavigationGestures={true}></WebView>)}
283
286
  </Portal>);
284
287
  });
285
288
  _WebView.displayName = 'MpxWebview';
@@ -30,9 +30,6 @@ export const createFaces = (itemHeight, visibleCount) => {
30
30
  for (let i = 0; i < index; i++) {
31
31
  offset += freeSpaces[i];
32
32
  }
33
- if (index === 0) {
34
- offset *= 0.6;
35
- }
36
33
  return offset;
37
34
  });
38
35
  return [screenHeights, offsets];
@@ -41,9 +38,7 @@ export const createFaces = (itemHeight, visibleCount) => {
41
38
  const map = {
42
39
  0: 0,
43
40
  1: 0.8,
44
- 2: 0.9 // 0.35
45
- // 3: 0.45, // 0.45
46
- // 4: 0.5 // 0.5
41
+ 2: 0.9
47
42
  };
48
43
  return map[index] ?? Math.min(1, map[2] + index * 0.05);
49
44
  };
@@ -139,20 +139,23 @@ export default function useAnimationHooks(props) {
139
139
  if (enableAnimationRef.current !== enableStyleAnimation) {
140
140
  error('[Mpx runtime error]: animation use should be stable in the component lifecycle, or you can set [enable-animation] with true.');
141
141
  }
142
- if (!enableStyleAnimation)
143
- return { enableStyleAnimation };
142
+ if (!enableAnimationRef.current)
143
+ return { enableStyleAnimation: false };
144
144
  const originalStyle = formatStyle(style);
145
145
  // id 标识
146
146
  const id = animation?.id || -1;
147
147
  // 有动画样式的 style key
148
+ // eslint-disable-next-line react-hooks/rules-of-hooks
148
149
  const animatedStyleKeys = useSharedValue([]);
149
150
  // 记录动画key的style样式值 没有的话设置为false
151
+ // eslint-disable-next-line react-hooks/rules-of-hooks
150
152
  const animatedKeys = useRef({});
151
153
  // const animatedKeys = useRef({} as {[propName: keyof ExtendedViewStyle]: boolean|number|string})
152
154
  // ** 全量 style prop sharedValue
153
155
  // 不能做增量的原因:
154
156
  // 1 尝试用 useRef,但 useAnimatedStyle 访问后的 ref 不能在增加新的值,被冻结
155
157
  // 2 尝试用 useSharedValue,因为实际触发的 style prop 需要是 sharedValue 才能驱动动画,若外层 shareValMap 也是 sharedValue,动画无法驱动。
158
+ // eslint-disable-next-line react-hooks/rules-of-hooks
156
159
  const shareValMap = useMemo(() => {
157
160
  return Object.keys(InitialValue).reduce((valMap, key) => {
158
161
  const defaultVal = getInitialVal(key, isTransform(key));
@@ -161,6 +164,7 @@ export default function useAnimationHooks(props) {
161
164
  }, {});
162
165
  }, []);
163
166
  // ** 获取动画样式prop & 驱动动画
167
+ // eslint-disable-next-line react-hooks/rules-of-hooks
164
168
  useEffect(() => {
165
169
  if (id === -1)
166
170
  return;
@@ -182,6 +186,7 @@ export default function useAnimationHooks(props) {
182
186
  // })
183
187
  // }, [style])
184
188
  // ** 清空动画
189
+ // eslint-disable-next-line react-hooks/rules-of-hooks
185
190
  useEffect(() => {
186
191
  return () => {
187
192
  Object.values(shareValMap).forEach((value) => {
@@ -214,14 +219,13 @@ export default function useAnimationHooks(props) {
214
219
  }
215
220
  // 添加每个key的多次step动画
216
221
  animatedKeys.forEach(key => {
222
+ const ruleV = isTransform(key) ? transform.get(key) : rules.get(key);
217
223
  // key不存在,第一轮取shareValMap[key]value,非第一轮取上一轮的
218
- const toVal = rules.get(key) !== undefined
219
- ? rules.get(key)
220
- : transform.get(key) !== undefined
221
- ? transform.get(key)
222
- : index > 0
223
- ? lastValueMap[key]
224
- : shareValMap[key].value;
224
+ const toVal = ruleV !== undefined
225
+ ? ruleV
226
+ : index > 0
227
+ ? lastValueMap[key]
228
+ : shareValMap[key].value;
225
229
  const animation = getAnimation({ key, value: toVal }, { delay, duration, easing }, needSetCallback ? setTransformOrigin : undefined);
226
230
  needSetCallback = false;
227
231
  if (!sequence[key]) {
@@ -315,6 +319,7 @@ export default function useAnimationHooks(props) {
315
319
  }, {});
316
320
  }
317
321
  // ** 生成动画样式
322
+ // eslint-disable-next-line react-hooks/rules-of-hooks
318
323
  const animationStyle = useAnimatedStyle(() => {
319
324
  // console.info(`useAnimatedStyle styles=`, originalStyle)
320
325
  return animatedStyleKeys.value.reduce((styles, key) => {
@@ -335,7 +340,7 @@ export default function useAnimationHooks(props) {
335
340
  }, {});
336
341
  });
337
342
  return {
338
- enableStyleAnimation,
343
+ enableStyleAnimation: enableAnimationRef.current,
339
344
  animationStyle
340
345
  };
341
346
  }
@@ -559,3 +559,60 @@ export function useHoverStyle({ hoverStyle, hoverStartTime, hoverStayTime, disab
559
559
  enableHoverStyle
560
560
  };
561
561
  }
562
+ export function useHover({ enableHover, hoverStartTime, hoverStayTime, disabled }) {
563
+ const enableHoverRef = useRef(enableHover);
564
+ if (enableHoverRef.current !== enableHover) {
565
+ error('[Mpx runtime error]: hover-class use should be stable in the component lifecycle.');
566
+ }
567
+ if (!enableHoverRef.current)
568
+ return { isHover: false };
569
+ // eslint-disable-next-line react-hooks/rules-of-hooks
570
+ const gestureRef = useContext(ScrollViewContext).gestureRef;
571
+ // eslint-disable-next-line react-hooks/rules-of-hooks
572
+ const [isHover, setIsHover] = useState(false);
573
+ // eslint-disable-next-line react-hooks/rules-of-hooks
574
+ const dataRef = useRef({});
575
+ // eslint-disable-next-line react-hooks/rules-of-hooks
576
+ useEffect(() => {
577
+ return () => {
578
+ dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer);
579
+ dataRef.current.stayTimer && clearTimeout(dataRef.current.stayTimer);
580
+ };
581
+ }, []);
582
+ const setStartTimer = () => {
583
+ if (disabled)
584
+ return;
585
+ dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer);
586
+ dataRef.current.startTimer = setTimeout(() => {
587
+ setIsHover(true);
588
+ }, +hoverStartTime);
589
+ };
590
+ const setStayTimer = () => {
591
+ if (disabled)
592
+ return;
593
+ dataRef.current.stayTimer && clearTimeout(dataRef.current.stayTimer);
594
+ dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer);
595
+ dataRef.current.stayTimer = setTimeout(() => {
596
+ setIsHover(false);
597
+ }, +hoverStayTime);
598
+ };
599
+ // eslint-disable-next-line react-hooks/rules-of-hooks
600
+ const gesture = useMemo(() => {
601
+ return Gesture.Pan()
602
+ .onTouchesDown(() => {
603
+ 'worklet';
604
+ runOnJS(setStartTimer)();
605
+ })
606
+ .onTouchesUp(() => {
607
+ 'worklet';
608
+ runOnJS(setStayTimer)();
609
+ });
610
+ }, []);
611
+ if (gestureRef) {
612
+ gesture.simultaneousWithExternalGesture(gestureRef);
613
+ }
614
+ return {
615
+ isHover,
616
+ gesture
617
+ };
618
+ }