@mpxjs/webpack-plugin 2.9.69-beta.1 → 2.9.69-beta.10
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/config.js +3 -1
- package/lib/platform/template/wx/index.js +3 -1
- package/lib/react/processScript.js +6 -4
- package/lib/runtime/components/react/context.ts +17 -0
- package/lib/runtime/components/react/dist/context.js +2 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +2 -2
- package/lib/runtime/components/react/dist/locale-provider.jsx +15 -0
- package/lib/runtime/components/react/dist/mpx-button.jsx +16 -44
- package/lib/runtime/components/react/dist/mpx-image.jsx +13 -9
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +65 -61
- package/lib/runtime/components/react/dist/mpx-portal/portal-consumer.jsx +23 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +93 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +40 -0
- package/lib/runtime/components/react/dist/mpx-portal.jsx +13 -0
- package/lib/runtime/components/react/dist/mpx-provider.jsx +31 -0
- package/lib/runtime/components/react/dist/mpx-root-portal.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +9 -5
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +13 -7
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +384 -321
- package/lib/runtime/components/react/dist/mpx-view.jsx +16 -20
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +129 -53
- package/lib/runtime/components/react/dist/pickerFaces.js +2 -7
- package/lib/runtime/components/react/dist/useAnimationHooks.js +30 -13
- package/lib/runtime/components/react/dist/utils.jsx +60 -2
- package/lib/runtime/components/react/getInnerListeners.ts +2 -2
- package/lib/runtime/components/react/locale-provider.tsx +83 -0
- package/lib/runtime/components/react/mpx-button.tsx +20 -57
- package/lib/runtime/components/react/mpx-image.tsx +41 -25
- package/lib/runtime/components/react/mpx-picker/time.tsx +2 -1
- package/lib/runtime/components/react/mpx-picker-view-column-item.tsx +3 -3
- package/lib/runtime/components/react/mpx-picker-view-column.tsx +70 -69
- package/lib/runtime/components/react/mpx-portal/portal-consumer.tsx +32 -0
- package/lib/runtime/components/react/mpx-portal/portal-host.tsx +127 -0
- package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +64 -0
- package/lib/runtime/components/react/mpx-portal.tsx +30 -0
- package/lib/runtime/components/react/mpx-provider.tsx +51 -0
- package/lib/runtime/components/react/mpx-root-portal.tsx +1 -1
- package/lib/runtime/components/react/mpx-scroll-view.tsx +10 -8
- package/lib/runtime/components/react/mpx-swiper-item.tsx +13 -7
- package/lib/runtime/components/react/mpx-swiper.tsx +378 -325
- package/lib/runtime/components/react/mpx-view.tsx +19 -22
- package/lib/runtime/components/react/mpx-web-view.tsx +170 -62
- package/lib/runtime/components/react/pickerFaces.ts +2 -7
- package/lib/runtime/components/react/types/global.d.ts +7 -0
- package/lib/runtime/components/react/useAnimationHooks.ts +34 -14
- package/lib/runtime/components/react/utils.tsx +67 -2
- package/lib/template-compiler/compiler.js +1 -1
- 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
|
// 预解析
|
|
@@ -535,7 +535,8 @@ function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backg
|
|
|
535
535
|
textProps
|
|
536
536
|
});
|
|
537
537
|
return [
|
|
538
|
-
|
|
538
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
539
|
+
enableBackground ? useWrapImage(backgroundStyle, innerStyle, enableFastImage) : null,
|
|
539
540
|
children
|
|
540
541
|
];
|
|
541
542
|
}
|
|
@@ -551,7 +552,8 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
551
552
|
flexWrap: 'nowrap'
|
|
552
553
|
}
|
|
553
554
|
: {};
|
|
554
|
-
const
|
|
555
|
+
const enableHover = !!hoverStyle;
|
|
556
|
+
const { isHover, gesture } = useHover({ enableHover, hoverStartTime, hoverStayTime });
|
|
555
557
|
const styleObj = extendObject({}, defaultStyle, style, isHover ? hoverStyle : {});
|
|
556
558
|
const { normalStyle, hasSelfPercent, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, {
|
|
557
559
|
enableVar,
|
|
@@ -572,20 +574,14 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
572
574
|
});
|
|
573
575
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
|
|
574
576
|
const viewStyle = extendObject({}, innerStyle, layoutStyle);
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
}
|
|
580
|
-
const finalStyle = enableAnimationRef.current
|
|
581
|
-
? [viewStyle, useAnimationHooks({
|
|
582
|
-
animation,
|
|
583
|
-
style: viewStyle
|
|
584
|
-
})]
|
|
585
|
-
: viewStyle;
|
|
577
|
+
const { enableStyleAnimation, animationStyle } = useAnimationHooks({
|
|
578
|
+
enableAnimation,
|
|
579
|
+
animation,
|
|
580
|
+
style: viewStyle
|
|
581
|
+
});
|
|
586
582
|
const innerProps = useInnerProps(props, extendObject({
|
|
587
583
|
ref: nodeRef,
|
|
588
|
-
style:
|
|
584
|
+
style: enableStyleAnimation ? [viewStyle, animationStyle] : viewStyle
|
|
589
585
|
}, layoutProps), [
|
|
590
586
|
'hover-start-time',
|
|
591
587
|
'hover-stay-time',
|
|
@@ -604,11 +600,11 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
604
600
|
innerStyle,
|
|
605
601
|
enableFastImage
|
|
606
602
|
});
|
|
607
|
-
const BaseComponent =
|
|
608
|
-
? createElement(Animated.View,
|
|
603
|
+
const BaseComponent = enableStyleAnimation
|
|
604
|
+
? createElement(Animated.View, innerProps, childNode)
|
|
609
605
|
: createElement(View, innerProps, childNode);
|
|
610
|
-
return
|
|
611
|
-
? createElement(GestureDetector, { gesture }, BaseComponent)
|
|
606
|
+
return enableHover
|
|
607
|
+
? createElement(GestureDetector, { gesture: gesture }, BaseComponent)
|
|
612
608
|
: BaseComponent;
|
|
613
609
|
});
|
|
614
610
|
_View.displayName = 'MpxView';
|
|
@@ -1,22 +1,61 @@
|
|
|
1
|
-
import { forwardRef, useRef, useContext, useMemo,
|
|
2
|
-
import { warn,
|
|
3
|
-
import
|
|
1
|
+
import { forwardRef, useRef, useContext, useMemo, useState, useCallback, useEffect } from 'react';
|
|
2
|
+
import { warn, isFunction } from '@mpxjs/utils';
|
|
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
|
|
8
|
+
import { getCurrentPage } from './utils';
|
|
9
|
+
import { useNavigation } from '@react-navigation/native';
|
|
9
10
|
import { RouteContext } from './context';
|
|
10
|
-
import { BackHandler } from 'react-native';
|
|
11
|
+
import { BackHandler, StyleSheet, View, Text } from 'react-native';
|
|
12
|
+
const styles = StyleSheet.create({
|
|
13
|
+
loadErrorContext: {
|
|
14
|
+
display: 'flex',
|
|
15
|
+
alignItems: 'center'
|
|
16
|
+
},
|
|
17
|
+
loadErrorText: {
|
|
18
|
+
fontSize: 12,
|
|
19
|
+
color: '#666666',
|
|
20
|
+
paddingTop: '40%',
|
|
21
|
+
paddingBottom: 20,
|
|
22
|
+
paddingLeft: '10%',
|
|
23
|
+
paddingRight: '10%',
|
|
24
|
+
textAlign: 'center'
|
|
25
|
+
},
|
|
26
|
+
loadErrorButton: {
|
|
27
|
+
color: '#666666',
|
|
28
|
+
textAlign: 'center',
|
|
29
|
+
padding: 10,
|
|
30
|
+
borderColor: '#666666',
|
|
31
|
+
borderStyle: 'solid',
|
|
32
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
33
|
+
borderRadius: 10
|
|
34
|
+
}
|
|
35
|
+
});
|
|
11
36
|
const _WebView = forwardRef((props, ref) => {
|
|
12
37
|
const { src, bindmessage, bindload, binderror } = props;
|
|
13
38
|
const mpx = global.__mpx;
|
|
39
|
+
const errorText = {
|
|
40
|
+
'zh-CN': {
|
|
41
|
+
text: '网络不可用,请检查网络设置',
|
|
42
|
+
button: '重新加载'
|
|
43
|
+
},
|
|
44
|
+
'en-US': {
|
|
45
|
+
text: 'The network is not available. Please check the network settings',
|
|
46
|
+
button: 'Reload'
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const currentErrorText = errorText[mpx.i18n.locale || 'zh-CN'];
|
|
14
50
|
if (props.style) {
|
|
15
51
|
warn('The web-view component does not support the style prop.');
|
|
16
52
|
}
|
|
17
53
|
const pageId = useContext(RouteContext);
|
|
54
|
+
const [pageLoadErr, setPageLoadErr] = useState(false);
|
|
18
55
|
const currentPage = useMemo(() => getCurrentPage(pageId), [pageId]);
|
|
19
56
|
const webViewRef = useRef(null);
|
|
57
|
+
const [isLoaded, setIsLoaded] = useState(true);
|
|
58
|
+
const fristLoaded = useRef(false);
|
|
20
59
|
const defaultWebViewStyle = {
|
|
21
60
|
position: 'absolute',
|
|
22
61
|
left: 0,
|
|
@@ -25,6 +64,7 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
25
64
|
bottom: 0
|
|
26
65
|
};
|
|
27
66
|
const canGoBack = useRef(false);
|
|
67
|
+
const isNavigateBack = useRef(false);
|
|
28
68
|
const onAndroidBackPress = useCallback(() => {
|
|
29
69
|
if (canGoBack.current) {
|
|
30
70
|
webViewRef.current?.goBack();
|
|
@@ -33,20 +73,27 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
33
73
|
return false;
|
|
34
74
|
}, [canGoBack]);
|
|
35
75
|
const beforeRemoveHandle = useCallback((e) => {
|
|
36
|
-
if (canGoBack.current) {
|
|
76
|
+
if (canGoBack.current && !isNavigateBack.current) {
|
|
37
77
|
webViewRef.current?.goBack();
|
|
38
78
|
e.preventDefault();
|
|
39
79
|
}
|
|
80
|
+
isNavigateBack.current = false;
|
|
40
81
|
}, [canGoBack]);
|
|
41
|
-
const navigation =
|
|
42
|
-
navigation?.addListener('beforeRemove', beforeRemoveHandle);
|
|
82
|
+
const navigation = useNavigation();
|
|
43
83
|
useEffect(() => {
|
|
44
84
|
if (__mpx_mode__ === 'android') {
|
|
45
85
|
BackHandler.addEventListener('hardwareBackPress', onAndroidBackPress);
|
|
46
|
-
return () => {
|
|
47
|
-
BackHandler.removeEventListener('hardwareBackPress', onAndroidBackPress);
|
|
48
|
-
};
|
|
49
86
|
}
|
|
87
|
+
const addListener = navigation?.addListener.bind(navigation);
|
|
88
|
+
const beforeRemoveSubscription = addListener?.('beforeRemove', beforeRemoveHandle);
|
|
89
|
+
return () => {
|
|
90
|
+
if (__mpx_mode__ === 'android') {
|
|
91
|
+
BackHandler.removeEventListener('hardwareBackPress', onAndroidBackPress);
|
|
92
|
+
}
|
|
93
|
+
if (isFunction(beforeRemoveSubscription)) {
|
|
94
|
+
beforeRemoveSubscription();
|
|
95
|
+
}
|
|
96
|
+
};
|
|
50
97
|
}, []);
|
|
51
98
|
useNodesRef(props, ref, webViewRef, {
|
|
52
99
|
style: defaultWebViewStyle
|
|
@@ -54,25 +101,11 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
54
101
|
if (!src) {
|
|
55
102
|
return null;
|
|
56
103
|
}
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
src: res.nativeEvent?.url
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
bindload(result);
|
|
66
|
-
};
|
|
67
|
-
const _error = function (res) {
|
|
68
|
-
const result = {
|
|
69
|
-
type: 'error',
|
|
70
|
-
timeStamp: res.timeStamp,
|
|
71
|
-
detail: {
|
|
72
|
-
src: ''
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
binderror(result);
|
|
104
|
+
const _reload = function () {
|
|
105
|
+
if (__mpx_mode__ === 'android') {
|
|
106
|
+
fristLoaded.current = false; // 安卓需要重新设置
|
|
107
|
+
}
|
|
108
|
+
setPageLoadErr(false);
|
|
76
109
|
};
|
|
77
110
|
const injectedJavaScript = `
|
|
78
111
|
if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
|
|
@@ -102,7 +135,7 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
102
135
|
`;
|
|
103
136
|
const sendMessage = function (params) {
|
|
104
137
|
return `
|
|
105
|
-
window.mpxWebviewMessageCallback(${params})
|
|
138
|
+
window.mpxWebviewMessageCallback && window.mpxWebviewMessageCallback(${params})
|
|
106
139
|
true;
|
|
107
140
|
`;
|
|
108
141
|
};
|
|
@@ -155,6 +188,7 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
155
188
|
asyncCallback = navObj.navigateTo(...params);
|
|
156
189
|
break;
|
|
157
190
|
case 'navigateBack':
|
|
191
|
+
isNavigateBack.current = true;
|
|
158
192
|
asyncCallback = navObj.navigateBack(...params);
|
|
159
193
|
break;
|
|
160
194
|
case 'redirectTo':
|
|
@@ -201,28 +235,70 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
201
235
|
}
|
|
202
236
|
});
|
|
203
237
|
};
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
238
|
+
let isLoadError = false;
|
|
239
|
+
let statusCode = '';
|
|
240
|
+
const onLoadEndHandle = function (res) {
|
|
241
|
+
fristLoaded.current = true;
|
|
242
|
+
setIsLoaded(true);
|
|
243
|
+
const src = res.nativeEvent?.url;
|
|
244
|
+
if (isLoadError) {
|
|
245
|
+
isLoadError = false;
|
|
246
|
+
isNavigateBack.current = false;
|
|
247
|
+
const result = {
|
|
248
|
+
type: 'error',
|
|
249
|
+
timeStamp: res.timeStamp,
|
|
250
|
+
detail: {
|
|
251
|
+
src,
|
|
252
|
+
statusCode
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
binderror && binderror(result);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
const result = {
|
|
259
|
+
type: 'load',
|
|
260
|
+
timeStamp: res.timeStamp,
|
|
261
|
+
detail: {
|
|
262
|
+
src
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
bindload?.(result);
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
const onLoadEnd = function (res) {
|
|
269
|
+
if (__mpx_mode__ === 'android') {
|
|
270
|
+
setTimeout(() => {
|
|
271
|
+
onLoadEndHandle(res);
|
|
272
|
+
}, 0);
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
onLoadEndHandle(res);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
const onHttpError = function (res) {
|
|
279
|
+
isLoadError = true;
|
|
280
|
+
statusCode = res.nativeEvent?.statusCode;
|
|
281
|
+
};
|
|
282
|
+
const onError = function () {
|
|
283
|
+
statusCode = '';
|
|
284
|
+
isLoadError = true;
|
|
285
|
+
if (!fristLoaded.current) {
|
|
286
|
+
setPageLoadErr(true);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
const onLoadStart = function () {
|
|
290
|
+
if (!fristLoaded.current) {
|
|
291
|
+
setIsLoaded(false);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
return (<Portal key={pageLoadErr ? 'error' : 'webview'}>
|
|
295
|
+
{pageLoadErr
|
|
296
|
+
? (<View style={[styles.loadErrorContext, defaultWebViewStyle]}>
|
|
297
|
+
<View style={styles.loadErrorText}><Text style={{ fontSize: 14, color: '#999999' }}>{currentErrorText.text}</Text></View>
|
|
298
|
+
<View style={styles.loadErrorButton} onTouchEnd={_reload}><Text style={{ fontSize: 12, color: '#666666' }}>{currentErrorText.button}</Text></View>
|
|
299
|
+
</View>)
|
|
300
|
+
: (<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>)}
|
|
301
|
+
</Portal>);
|
|
226
302
|
});
|
|
227
303
|
_WebView.displayName = 'MpxWebview';
|
|
228
304
|
export default _WebView;
|
|
@@ -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,15 +38,13 @@ 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
|
};
|
|
50
45
|
const degrees = getDegreesRelativeCenter();
|
|
51
46
|
const [screenHeight, offsets] = getScreenHeightsAndOffsets(degrees);
|
|
52
|
-
const scales = [
|
|
47
|
+
const scales = [0.973, 0.9, 0.8];
|
|
53
48
|
return [
|
|
54
49
|
// top items
|
|
55
50
|
...degrees
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef } from 'react';
|
|
2
2
|
import { Easing, useSharedValue, withTiming, useAnimatedStyle, withSequence, withDelay, makeMutable, cancelAnimation } from 'react-native-reanimated';
|
|
3
|
+
import { error } from '@mpxjs/utils';
|
|
3
4
|
// 微信 timingFunction 和 RN Easing 对应关系
|
|
4
5
|
const EasingKey = {
|
|
5
6
|
linear: Easing.linear,
|
|
6
|
-
ease: Easing.ease,
|
|
7
|
-
'ease-in': Easing.in(Easing.
|
|
8
|
-
'ease-in-out': Easing.inOut(Easing.
|
|
9
|
-
'ease-out': Easing.out(Easing.
|
|
7
|
+
ease: Easing.inOut(Easing.ease),
|
|
8
|
+
'ease-in': Easing.in(Easing.poly(3)),
|
|
9
|
+
'ease-in-out': Easing.inOut(Easing.poly(3)),
|
|
10
|
+
'ease-out': Easing.out(Easing.poly(3))
|
|
10
11
|
// 'step-start': '',
|
|
11
12
|
// 'step-end': ''
|
|
12
13
|
};
|
|
@@ -132,19 +133,29 @@ const formatStyle = (style) => {
|
|
|
132
133
|
});
|
|
133
134
|
};
|
|
134
135
|
export default function useAnimationHooks(props) {
|
|
135
|
-
const { style = {}, animation } = props;
|
|
136
|
+
const { style = {}, animation, enableAnimation } = props;
|
|
137
|
+
const enableStyleAnimation = enableAnimation || !!animation;
|
|
138
|
+
const enableAnimationRef = useRef(enableStyleAnimation);
|
|
139
|
+
if (enableAnimationRef.current !== enableStyleAnimation) {
|
|
140
|
+
error('[Mpx runtime error]: animation use should be stable in the component lifecycle, or you can set [enable-animation] with true.');
|
|
141
|
+
}
|
|
142
|
+
if (!enableAnimationRef.current)
|
|
143
|
+
return { enableStyleAnimation: false };
|
|
136
144
|
const originalStyle = formatStyle(style);
|
|
137
145
|
// id 标识
|
|
138
146
|
const id = animation?.id || -1;
|
|
139
147
|
// 有动画样式的 style key
|
|
148
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
140
149
|
const animatedStyleKeys = useSharedValue([]);
|
|
141
150
|
// 记录动画key的style样式值 没有的话设置为false
|
|
151
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
142
152
|
const animatedKeys = useRef({});
|
|
143
153
|
// const animatedKeys = useRef({} as {[propName: keyof ExtendedViewStyle]: boolean|number|string})
|
|
144
154
|
// ** 全量 style prop sharedValue
|
|
145
155
|
// 不能做增量的原因:
|
|
146
156
|
// 1 尝试用 useRef,但 useAnimatedStyle 访问后的 ref 不能在增加新的值,被冻结
|
|
147
157
|
// 2 尝试用 useSharedValue,因为实际触发的 style prop 需要是 sharedValue 才能驱动动画,若外层 shareValMap 也是 sharedValue,动画无法驱动。
|
|
158
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
148
159
|
const shareValMap = useMemo(() => {
|
|
149
160
|
return Object.keys(InitialValue).reduce((valMap, key) => {
|
|
150
161
|
const defaultVal = getInitialVal(key, isTransform(key));
|
|
@@ -153,6 +164,7 @@ export default function useAnimationHooks(props) {
|
|
|
153
164
|
}, {});
|
|
154
165
|
}, []);
|
|
155
166
|
// ** 获取动画样式prop & 驱动动画
|
|
167
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
156
168
|
useEffect(() => {
|
|
157
169
|
if (id === -1)
|
|
158
170
|
return;
|
|
@@ -174,6 +186,7 @@ export default function useAnimationHooks(props) {
|
|
|
174
186
|
// })
|
|
175
187
|
// }, [style])
|
|
176
188
|
// ** 清空动画
|
|
189
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
177
190
|
useEffect(() => {
|
|
178
191
|
return () => {
|
|
179
192
|
Object.values(shareValMap).forEach((value) => {
|
|
@@ -206,14 +219,13 @@ export default function useAnimationHooks(props) {
|
|
|
206
219
|
}
|
|
207
220
|
// 添加每个key的多次step动画
|
|
208
221
|
animatedKeys.forEach(key => {
|
|
222
|
+
const ruleV = isTransform(key) ? transform.get(key) : rules.get(key);
|
|
209
223
|
// key不存在,第一轮取shareValMap[key]value,非第一轮取上一轮的
|
|
210
|
-
const toVal =
|
|
211
|
-
?
|
|
212
|
-
:
|
|
213
|
-
?
|
|
214
|
-
:
|
|
215
|
-
? lastValueMap[key]
|
|
216
|
-
: shareValMap[key].value;
|
|
224
|
+
const toVal = ruleV !== undefined
|
|
225
|
+
? ruleV
|
|
226
|
+
: index > 0
|
|
227
|
+
? lastValueMap[key]
|
|
228
|
+
: shareValMap[key].value;
|
|
217
229
|
const animation = getAnimation({ key, value: toVal }, { delay, duration, easing }, needSetCallback ? setTransformOrigin : undefined);
|
|
218
230
|
needSetCallback = false;
|
|
219
231
|
if (!sequence[key]) {
|
|
@@ -307,7 +319,8 @@ export default function useAnimationHooks(props) {
|
|
|
307
319
|
}, {});
|
|
308
320
|
}
|
|
309
321
|
// ** 生成动画样式
|
|
310
|
-
|
|
322
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
323
|
+
const animationStyle = useAnimatedStyle(() => {
|
|
311
324
|
// console.info(`useAnimatedStyle styles=`, originalStyle)
|
|
312
325
|
return animatedStyleKeys.value.reduce((styles, key) => {
|
|
313
326
|
// console.info('getAnimationStyles', key, shareValMap[key].value)
|
|
@@ -326,4 +339,8 @@ export default function useAnimationHooks(props) {
|
|
|
326
339
|
return styles;
|
|
327
340
|
}, {});
|
|
328
341
|
});
|
|
342
|
+
return {
|
|
343
|
+
enableStyleAnimation: enableAnimationRef.current,
|
|
344
|
+
animationStyle
|
|
345
|
+
};
|
|
329
346
|
}
|
|
@@ -451,13 +451,14 @@ export function wrapChildren(props = {}, { hasVarDec, varContext, textStyle, tex
|
|
|
451
451
|
export const debounce = (func, delay) => {
|
|
452
452
|
let timer;
|
|
453
453
|
const wrapper = (...args) => {
|
|
454
|
-
clearTimeout(timer);
|
|
454
|
+
timer && clearTimeout(timer);
|
|
455
455
|
timer = setTimeout(() => {
|
|
456
456
|
func(...args);
|
|
457
457
|
}, delay);
|
|
458
458
|
};
|
|
459
459
|
wrapper.clear = () => {
|
|
460
|
-
clearTimeout(timer);
|
|
460
|
+
timer && clearTimeout(timer);
|
|
461
|
+
timer = null;
|
|
461
462
|
};
|
|
462
463
|
return wrapper;
|
|
463
464
|
};
|
|
@@ -558,3 +559,60 @@ export function useHoverStyle({ hoverStyle, hoverStartTime, hoverStayTime, disab
|
|
|
558
559
|
enableHoverStyle
|
|
559
560
|
};
|
|
560
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
|
+
}
|
|
@@ -126,8 +126,8 @@ function checkIsNeedPress (e: NativeTouchEvent, type: 'bubble' | 'capture', ref:
|
|
|
126
126
|
const currentPageX = nativeEvent.changedTouches[0].pageX
|
|
127
127
|
const currentPageY = nativeEvent.changedTouches[0].pageY
|
|
128
128
|
if (
|
|
129
|
-
Math.abs(currentPageX - tapDetailInfo.x) >
|
|
130
|
-
Math.abs(currentPageY - tapDetailInfo.y) >
|
|
129
|
+
Math.abs(currentPageX - tapDetailInfo.x) > 3 ||
|
|
130
|
+
Math.abs(currentPageY - tapDetailInfo.y) > 3
|
|
131
131
|
) {
|
|
132
132
|
ref.current!.needPress[type] = false
|
|
133
133
|
ref.current!.startTimer[type] &&
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createContext, useMemo, memo, ReactNode } from 'react'
|
|
2
|
+
import { extendObject } from './utils'
|
|
3
|
+
|
|
4
|
+
interface Locale {
|
|
5
|
+
/** zh_CN */
|
|
6
|
+
locale: string
|
|
7
|
+
DatePicker: {
|
|
8
|
+
/** 确定 */
|
|
9
|
+
okText: string
|
|
10
|
+
/** 取消 */
|
|
11
|
+
dismissText: string
|
|
12
|
+
/** 请选择 */
|
|
13
|
+
extra: string
|
|
14
|
+
DatePickerLocale: {
|
|
15
|
+
/** 年 */
|
|
16
|
+
year: string
|
|
17
|
+
/** 月 */
|
|
18
|
+
month: string
|
|
19
|
+
/** 日 */
|
|
20
|
+
day: string
|
|
21
|
+
/** 时 */
|
|
22
|
+
hour: string
|
|
23
|
+
/** 分 */
|
|
24
|
+
minute: string
|
|
25
|
+
/** 上午 */
|
|
26
|
+
am: string
|
|
27
|
+
/** 下午 */
|
|
28
|
+
pm: string
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
DatePickerView: {
|
|
32
|
+
/** 年 */
|
|
33
|
+
year: string
|
|
34
|
+
/** 月 */
|
|
35
|
+
month: string
|
|
36
|
+
/** 日 */
|
|
37
|
+
day: string
|
|
38
|
+
/** 时 */
|
|
39
|
+
hour: string
|
|
40
|
+
/** 分 */
|
|
41
|
+
minute: string
|
|
42
|
+
/** 上午 */
|
|
43
|
+
am: string
|
|
44
|
+
/** 下午 */
|
|
45
|
+
pm: string
|
|
46
|
+
}
|
|
47
|
+
Picker: {
|
|
48
|
+
/** 确定 */
|
|
49
|
+
okText: string
|
|
50
|
+
/** 取消 */
|
|
51
|
+
dismissText: string
|
|
52
|
+
/** 请选择 */
|
|
53
|
+
extra: string
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export type LocaleContextProps = {
|
|
57
|
+
antLocale: Partial<Locale & { exist: boolean }>
|
|
58
|
+
}
|
|
59
|
+
export interface LocaleProviderProps {
|
|
60
|
+
children?: ReactNode,
|
|
61
|
+
locale?: LocaleContextProps
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const LocaleContext = createContext<
|
|
65
|
+
LocaleContextProps | undefined
|
|
66
|
+
>(undefined)
|
|
67
|
+
|
|
68
|
+
const LocaleProvider = (props :LocaleProviderProps): JSX.Element => {
|
|
69
|
+
const locale = useMemo(() => {
|
|
70
|
+
return {
|
|
71
|
+
antLocale: extendObject({}, props.locale, { exist: true })
|
|
72
|
+
}
|
|
73
|
+
}, [props.locale])
|
|
74
|
+
return (
|
|
75
|
+
<LocaleContext.Provider value={locale}>
|
|
76
|
+
{props.children}
|
|
77
|
+
</LocaleContext.Provider>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
LocaleProvider.displayName = 'LocaleProvider'
|
|
82
|
+
|
|
83
|
+
export default memo(LocaleProvider)
|