@mpxjs/webpack-plugin 2.9.69-beta.4 → 2.9.69-beta.6

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 (30) hide show
  1. package/lib/runtime/components/react/context.ts +1 -1
  2. package/lib/runtime/components/react/dist/mpx-button.jsx +11 -11
  3. package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +1 -1
  4. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +16 -2
  5. package/lib/runtime/components/react/dist/mpx-portal/portal-consumer.jsx +1 -1
  6. package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +10 -41
  7. package/lib/runtime/components/react/dist/mpx-portal.jsx +1 -0
  8. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +13 -7
  9. package/lib/runtime/components/react/dist/mpx-swiper.jsx +382 -325
  10. package/lib/runtime/components/react/dist/mpx-view.jsx +15 -13
  11. package/lib/runtime/components/react/dist/mpx-web-view.jsx +19 -32
  12. package/lib/runtime/components/react/dist/pickerFaces.js +1 -6
  13. package/lib/runtime/components/react/dist/useAnimationHooks.js +15 -10
  14. package/lib/runtime/components/react/dist/utils.jsx +57 -0
  15. package/lib/runtime/components/react/mpx-button.tsx +12 -13
  16. package/lib/runtime/components/react/mpx-picker-view-column-item.tsx +1 -1
  17. package/lib/runtime/components/react/mpx-picker-view-column.tsx +18 -2
  18. package/lib/runtime/components/react/mpx-portal/portal-consumer.tsx +1 -1
  19. package/lib/runtime/components/react/mpx-portal/portal-host.tsx +14 -45
  20. package/lib/runtime/components/react/mpx-portal.tsx +1 -0
  21. package/lib/runtime/components/react/mpx-swiper-item.tsx +13 -7
  22. package/lib/runtime/components/react/mpx-swiper.tsx +377 -330
  23. package/lib/runtime/components/react/mpx-view.tsx +17 -14
  24. package/lib/runtime/components/react/mpx-web-view.tsx +19 -32
  25. package/lib/runtime/components/react/pickerFaces.ts +1 -6
  26. package/lib/runtime/components/react/types/global.d.ts +4 -0
  27. package/lib/runtime/components/react/useAnimationHooks.ts +14 -10
  28. package/lib/runtime/components/react/utils.tsx +64 -0
  29. package/lib/wxss/loader.js +15 -2
  30. package/package.json +1 -1
@@ -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
8
  import { getCurrentPage, extendObject } 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',
@@ -61,6 +62,7 @@ const _WebView = forwardRef((props, ref) => {
61
62
  bottom: 0
62
63
  };
63
64
  const canGoBack = useRef(false);
65
+ const isNavigateBack = useRef(false);
64
66
  const onAndroidBackPress = useCallback(() => {
65
67
  if (canGoBack.current) {
66
68
  webViewRef.current?.goBack();
@@ -69,42 +71,27 @@ const _WebView = forwardRef((props, ref) => {
69
71
  return false;
70
72
  }, [canGoBack]);
71
73
  const beforeRemoveHandle = useCallback((e) => {
72
- if (canGoBack.current) {
74
+ if (canGoBack.current && !isNavigateBack.current) {
73
75
  webViewRef.current?.goBack();
74
76
  e.preventDefault();
75
77
  }
78
+ isNavigateBack.current = false;
76
79
  }, [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);
80
+ const navigation = useNavigation();
100
81
  useEffect(() => {
101
82
  if (__mpx_mode__ === 'android') {
102
83
  BackHandler.addEventListener('hardwareBackPress', onAndroidBackPress);
103
- return () => {
104
- BackHandler.removeEventListener('hardwareBackPress', onAndroidBackPress);
105
- navigation?.removeListener('beforeRemove', beforeRemoveHandle);
106
- };
107
84
  }
85
+ const addListener = navigation?.addListener.bind(navigation);
86
+ const beforeRemoveSubscription = addListener?.('beforeRemove', beforeRemoveHandle);
87
+ return () => {
88
+ if (__mpx_mode__ === 'android') {
89
+ BackHandler.removeEventListener('hardwareBackPress', onAndroidBackPress);
90
+ }
91
+ if (isFunction(beforeRemoveSubscription)) {
92
+ beforeRemoveSubscription();
93
+ }
94
+ };
108
95
  }, []);
109
96
  useNodesRef(props, ref, webViewRef, {
110
97
  style: defaultWebViewStyle
@@ -159,7 +146,6 @@ const _WebView = forwardRef((props, ref) => {
159
146
  return _documentTitle
160
147
  }
161
148
  });
162
- ${hashInjectedJavascript}
163
149
  }
164
150
  true;
165
151
  `;
@@ -218,6 +204,7 @@ const _WebView = forwardRef((props, ref) => {
218
204
  asyncCallback = navObj.navigateTo(...params);
219
205
  break;
220
206
  case 'navigateBack':
207
+ isNavigateBack.current = true;
221
208
  asyncCallback = navObj.navigateBack(...params);
222
209
  break;
223
210
  case 'redirectTo':
@@ -279,7 +266,7 @@ const _WebView = forwardRef((props, ref) => {
279
266
  <View style={styles.loadErrorText}><Text style={{ fontSize: 14, color: '#999999' }}>{currentErrorText.text}</Text></View>
280
267
  <View style={styles.loadErrorButton} onTouchEnd={_reload}><Text style={{ fontSize: 12, color: '#666666' }}>{currentErrorText.button}</Text></View>
281
268
  </View>)
282
- : (<WebView style={defaultWebViewStyle} source={source} ref={webViewRef} javaScriptEnabled={true} onNavigationStateChange={_changeUrl} onMessage={_message} injectedJavaScript={injectedJavaScript} onLoadProgress={_onLoadProgress} allowsBackForwardNavigationGestures={true} {...events}></WebView>)}
269
+ : (<WebView style={defaultWebViewStyle} source={{ uri: src }} ref={webViewRef} javaScriptEnabled={true} onNavigationStateChange={_changeUrl} onMessage={_message} injectedJavaScript={injectedJavaScript} onLoadProgress={_onLoadProgress} allowsBackForwardNavigationGestures={true} {...events}></WebView>)}
283
270
  </Portal>);
284
271
  });
285
272
  _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
+ }
@@ -45,8 +45,8 @@ import {
45
45
  NativeSyntheticEvent
46
46
  } from 'react-native'
47
47
  import { warn } from '@mpxjs/utils'
48
- import { GestureDetector } from 'react-native-gesture-handler'
49
- import { getCurrentPage, splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren, extendObject, useHoverStyle } from './utils'
48
+ import { GestureDetector, PanGesture } from 'react-native-gesture-handler'
49
+ import { getCurrentPage, splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren, extendObject, useHover } from './utils'
50
50
  import useInnerProps, { getCustomEvent } from './getInnerListeners'
51
51
  import useNodesRef, { HandlerRef } from './useNodesRef'
52
52
  import { RouteContext, FormContext } from './context'
@@ -223,7 +223,8 @@ const Button = forwardRef<HandlerRef<View, ButtonProps>, ButtonProps>((buttonPro
223
223
 
224
224
  const formContext = useContext(FormContext)
225
225
 
226
- const { isHover, enableHoverStyle, gesture } = useHoverStyle({ hoverStyle, hoverStartTime, hoverStayTime, disabled })
226
+ const enableHover = hoverClass !== 'none'
227
+ const { isHover, gesture } = useHover({ enableHover, hoverStartTime, hoverStayTime, disabled })
227
228
 
228
229
  let submitFn: () => void | undefined
229
230
  let resetFn: () => void | undefined
@@ -235,15 +236,13 @@ const Button = forwardRef<HandlerRef<View, ButtonProps>, ButtonProps>((buttonPro
235
236
 
236
237
  const isMiniSize = size === 'mini'
237
238
 
238
- const applyHoverEffect = isHover && hoverClass !== 'none'
239
-
240
239
  const [color, hoverColor, plainColor, disabledColor] = TypeColorMap[type]
241
240
 
242
- const normalBackgroundColor = disabled ? disabledColor : applyHoverEffect || loading ? hoverColor : color
241
+ const normalBackgroundColor = disabled ? disabledColor : isHover || loading ? hoverColor : color
243
242
 
244
243
  const plainBorderColor = disabled
245
244
  ? 'rgba(0, 0, 0, .2)'
246
- : applyHoverEffect
245
+ : isHover
247
246
  ? `rgba(${plainColor},.6)`
248
247
  : `rgb(${plainColor})`
249
248
 
@@ -251,14 +250,14 @@ const Button = forwardRef<HandlerRef<View, ButtonProps>, ButtonProps>((buttonPro
251
250
 
252
251
  const plainTextColor = disabled
253
252
  ? 'rgba(0, 0, 0, .2)'
254
- : applyHoverEffect
253
+ : isHover
255
254
  ? `rgba(${plainColor}, .6)`
256
255
  : `rgb(${plainColor})`
257
256
 
258
257
  const normalTextColor =
259
258
  type === 'default'
260
- ? `rgba(0, 0, 0, ${disabled ? 0.3 : applyHoverEffect || loading ? 0.6 : 1})`
261
- : `rgba(255 ,255 ,255 , ${disabled || applyHoverEffect || loading ? 0.6 : 1})`
259
+ ? `rgba(0, 0, 0, ${disabled ? 0.3 : isHover || loading ? 0.6 : 1})`
260
+ : `rgba(255 ,255 ,255 , ${disabled || isHover || loading ? 0.6 : 1})`
262
261
 
263
262
  const viewStyle = {
264
263
  borderWidth: 1,
@@ -287,7 +286,7 @@ const Button = forwardRef<HandlerRef<View, ButtonProps>, ButtonProps>((buttonPro
287
286
  {},
288
287
  defaultStyle,
289
288
  style,
290
- applyHoverEffect ? hoverStyle : {}
289
+ isHover ? hoverStyle : {}
291
290
  )
292
291
 
293
292
  const {
@@ -414,8 +413,8 @@ const Button = forwardRef<HandlerRef<View, ButtonProps>, ButtonProps>((buttonPro
414
413
  )
415
414
  )
416
415
 
417
- return enableHoverStyle
418
- ? createElement(GestureDetector, { gesture }, baseButton)
416
+ return enableHover
417
+ ? createElement(GestureDetector, { gesture: gesture as PanGesture }, baseButton)
419
418
  : baseButton
420
419
  })
421
420
 
@@ -44,8 +44,8 @@ const _PickerViewColumnItem: React.FC<PickerColumnItemProps> = ({
44
44
  return {
45
45
  opacity: interpolate(offsetYShared.value, inputRange, facesShared.value.map((x) => x.opacity), Extrapolation.CLAMP),
46
46
  transform: [
47
- { rotateX: interpolate(offsetYShared.value, inputRange, facesShared.value.map((x) => x.deg), Extrapolation.CLAMP) + 'deg' },
48
47
  { translateY: interpolate(offsetYShared.value, inputRange, facesShared.value.map((x) => x.offsetY), Extrapolation.EXTEND) },
48
+ { rotateX: interpolate(offsetYShared.value, inputRange, facesShared.value.map((x) => x.deg), Extrapolation.CLAMP) + 'deg' },
49
49
  { scale: interpolate(offsetYShared.value, inputRange, facesShared.value.map((x) => x.scale), Extrapolation.EXTEND) }
50
50
  ]
51
51
  }
@@ -69,6 +69,7 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
69
69
  const prevScrollingInfo = useRef({ index: initialIndex, y: 0 })
70
70
  const touching = useRef(false)
71
71
  const scrolling = useRef(false)
72
+ const timerScrollTo = useRef<NodeJS.Timeout | null>(null)
72
73
  const activeIndex = useRef(initialIndex)
73
74
  const prevIndex = usePrevious(initialIndex)
74
75
  const prevMaxIndex = usePrevious(maxIndex)
@@ -125,6 +126,19 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
125
126
  })
126
127
  const debounceResetScrollPosition = useDebounceCallback(stableResetScrollPosition, 10)
127
128
 
129
+ const clearTimerScrollTo = () => {
130
+ if (timerScrollTo.current) {
131
+ clearTimeout(timerScrollTo.current)
132
+ timerScrollTo.current = null
133
+ }
134
+ }
135
+
136
+ useEffect(() => {
137
+ return () => {
138
+ clearTimerScrollTo()
139
+ }
140
+ }, [])
141
+
128
142
  useEffect(() => {
129
143
  if (
130
144
  !scrollViewRef.current ||
@@ -138,7 +152,8 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
138
152
  ) {
139
153
  return
140
154
  }
141
- setTimeout(() => {
155
+ clearTimerScrollTo()
156
+ timerScrollTo.current = setTimeout(() => {
142
157
  scrollViewRef.current?.scrollTo({
143
158
  x: 0,
144
159
  y: getYofIndex(initialIndex),
@@ -151,7 +166,8 @@ const _PickerViewColumn = forwardRef<HandlerRef<ScrollView & View, ColumnProps>,
151
166
  const onContentSizeChange = (_w: number, h: number) => {
152
167
  const y = getYofIndex(initialIndex)
153
168
  if (y <= h) {
154
- setTimeout(() => {
169
+ clearTimerScrollTo()
170
+ timerScrollTo.current = setTimeout(() => {
155
171
  scrollViewRef.current?.scrollTo({ x: 0, y, animated: false })
156
172
  }, 0)
157
173
  }
@@ -23,7 +23,7 @@ const PortalConsumer = ({ manager, children } :PortalConsumerProps): JSX.Element
23
23
  const curPageId = navigation?.pageId
24
24
  keyRef.current = manager.mount(children, undefined, curPageId)
25
25
  return () => {
26
- manager.unmount(keyRef.current, curPageId)
26
+ manager.unmount(keyRef.current)
27
27
  }
28
28
  }, [])
29
29
  return null
@@ -26,6 +26,7 @@ export type Operation =
26
26
  // events
27
27
  const addType = 'MPX_RN_ADD_PORTAL'
28
28
  const removeType = 'MPX_RN_REMOVE_PORTAL'
29
+ const updateType = 'MPX_RN_UPDATE_PORTAL'
29
30
  // fix react native web does not support DeviceEventEmitter
30
31
  const TopViewEventEmitter = DeviceEventEmitter || new NativeEventEmitter()
31
32
 
@@ -46,6 +47,10 @@ class PortalGuard {
46
47
  remove = (key: number) => {
47
48
  TopViewEventEmitter.emit(removeType, key)
48
49
  }
50
+
51
+ update = (key: number, e: ReactNode) => {
52
+ TopViewEventEmitter.emit(updateType, key, e)
53
+ }
49
54
  }
50
55
  /**
51
56
  * portal
@@ -57,6 +62,7 @@ const PortalHost = ({ children } :PortalHostProps): JSX.Element => {
57
62
  const _queue = useRef<Operation[]>([])
58
63
  const _addType = useRef<EventSubscription | null>(null)
59
64
  const _removeType = useRef<EventSubscription | null>(null)
65
+ const _updateType = useRef<EventSubscription | null>(null)
60
66
  const manager = useRef<PortalManagerContextValue | null>(null)
61
67
  let currentPageId: number | undefined
62
68
  const _mount = (children: ReactNode, _key?: number, curPageId?: number) => {
@@ -68,26 +74,17 @@ const PortalHost = ({ children } :PortalHostProps): JSX.Element => {
68
74
  const key = _key || _nextKey.current++
69
75
  if (manager.current) {
70
76
  manager.current.mount(key, children)
71
- } else {
72
- _queue.current.push({ type: 'mount', key, children })
73
77
  }
74
78
  return key
75
79
  }
76
80
 
77
- const _unmount = (key: number, curPageId?: number) => {
78
- const navigation = getFocusedNavigation()
79
- const pageId = navigation?.pageId
80
- if (pageId !== (curPageId ?? currentPageId)) {
81
- return
82
- }
81
+ const _unmount = (key: number) => {
83
82
  if (manager.current) {
84
83
  manager.current.unmount(key)
85
- } else {
86
- _queue.current.push({ type: 'unmount', key })
87
84
  }
88
85
  }
89
86
 
90
- const _update = (key: number, children: ReactNode, curPageId?: number) => {
87
+ const _update = (key: number, children?: ReactNode, curPageId?: number) => {
91
88
  const navigation = getFocusedNavigation()
92
89
  const pageId = navigation?.pageId
93
90
  if (pageId !== (curPageId ?? currentPageId)) {
@@ -95,17 +92,6 @@ const PortalHost = ({ children } :PortalHostProps): JSX.Element => {
95
92
  }
96
93
  if (manager.current) {
97
94
  manager.current.update(key, children)
98
- } else {
99
- const op: Operation = { type: 'mount', key, children }
100
- const index = _queue.current.findIndex(
101
- (o) => o.type === 'mount' || (o.type === 'update' && o.key === key)
102
- )
103
-
104
- if (index > -1) {
105
- _queue.current[index] = op
106
- } else {
107
- _queue.current.push(op)
108
- }
109
95
  }
110
96
  }
111
97
 
@@ -113,29 +99,13 @@ const PortalHost = ({ children } :PortalHostProps): JSX.Element => {
113
99
  const navigation = getFocusedNavigation()
114
100
  currentPageId = navigation?.pageId
115
101
  _addType.current = TopViewEventEmitter.addListener(addType, _mount)
116
- _removeType.current = TopViewEventEmitter.addListener(
117
- removeType,
118
- _unmount
119
- )
102
+ _removeType.current = TopViewEventEmitter.addListener(removeType, _unmount)
103
+ _updateType.current = TopViewEventEmitter.addListener(updateType, _update)
104
+
120
105
  return () => {
121
- while (_queue.current.length && manager.current) {
122
- const action = _queue.current.pop()
123
- if (!action) {
124
- continue
125
- }
126
- // tslint:disable-next-line:switch-default
127
- switch (action.type) {
128
- case 'mount':
129
- manager.current?.mount(action.key, action.children)
130
- break
131
- case 'update':
132
- manager.current?.update(action.key, action.children)
133
- break
134
- case 'unmount':
135
- manager.current?.unmount(action.key)
136
- break
137
- }
138
- }
106
+ _addType.current?.remove()
107
+ _removeType.current?.remove()
108
+ _updateType.current?.remove()
139
109
  }
140
110
  }, [])
141
111
  return (
@@ -146,7 +116,6 @@ const PortalHost = ({ children } :PortalHostProps): JSX.Element => {
146
116
  unmount: _unmount
147
117
  }}
148
118
  >
149
- {/* Need collapsable=false here to clip the elevations, otherwise they appear above Portal components */}
150
119
  <View style={styles.container} collapsable={false}>
151
120
  {children}
152
121
  </View>
@@ -25,5 +25,6 @@ const Portal = ({ children }:PortalProps): JSX.Element => {
25
25
  Portal.Host = PortalHost
26
26
  Portal.add = portal.add
27
27
  Portal.remove = portal.remove
28
+ Portal.update = portal.update
28
29
 
29
30
  export default Portal