@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.
- package/lib/runtime/components/react/context.ts +1 -1
- package/lib/runtime/components/react/dist/mpx-button.jsx +11 -11
- package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +16 -2
- package/lib/runtime/components/react/dist/mpx-portal/portal-consumer.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +10 -41
- package/lib/runtime/components/react/dist/mpx-portal.jsx +1 -0
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +13 -7
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +382 -325
- package/lib/runtime/components/react/dist/mpx-view.jsx +15 -13
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +19 -32
- package/lib/runtime/components/react/dist/pickerFaces.js +1 -6
- package/lib/runtime/components/react/dist/useAnimationHooks.js +15 -10
- package/lib/runtime/components/react/dist/utils.jsx +57 -0
- package/lib/runtime/components/react/mpx-button.tsx +12 -13
- package/lib/runtime/components/react/mpx-picker-view-column-item.tsx +1 -1
- package/lib/runtime/components/react/mpx-picker-view-column.tsx +18 -2
- package/lib/runtime/components/react/mpx-portal/portal-consumer.tsx +1 -1
- package/lib/runtime/components/react/mpx-portal/portal-host.tsx +14 -45
- package/lib/runtime/components/react/mpx-portal.tsx +1 -0
- package/lib/runtime/components/react/mpx-swiper-item.tsx +13 -7
- package/lib/runtime/components/react/mpx-swiper.tsx +377 -330
- package/lib/runtime/components/react/mpx-view.tsx +17 -14
- package/lib/runtime/components/react/mpx-web-view.tsx +19 -32
- package/lib/runtime/components/react/pickerFaces.ts +1 -6
- package/lib/runtime/components/react/types/global.d.ts +4 -0
- package/lib/runtime/components/react/useAnimationHooks.ts +14 -10
- package/lib/runtime/components/react/utils.tsx +64 -0
- package/lib/wxss/loader.js +15 -2
- 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,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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 =
|
|
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={
|
|
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
|
|
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 (!
|
|
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 =
|
|
219
|
-
?
|
|
220
|
-
:
|
|
221
|
-
?
|
|
222
|
-
:
|
|
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,
|
|
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
|
|
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 :
|
|
241
|
+
const normalBackgroundColor = disabled ? disabledColor : isHover || loading ? hoverColor : color
|
|
243
242
|
|
|
244
243
|
const plainBorderColor = disabled
|
|
245
244
|
? 'rgba(0, 0, 0, .2)'
|
|
246
|
-
:
|
|
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
|
-
:
|
|
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 :
|
|
261
|
-
: `rgba(255 ,255 ,255 , ${disabled ||
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
)
|
|
102
|
+
_removeType.current = TopViewEventEmitter.addListener(removeType, _unmount)
|
|
103
|
+
_updateType.current = TopViewEventEmitter.addListener(updateType, _update)
|
|
104
|
+
|
|
120
105
|
return () => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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>
|