@mpxjs/webpack-plugin 2.10.1 → 2.10.3
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/dependencies/RecordPageConfigsMapDependency.js +45 -0
- package/lib/index.js +23 -1
- package/lib/platform/style/wx/index.js +6 -4
- package/lib/platform/template/wx/component-config/input.js +1 -1
- package/lib/platform/template/wx/component-config/textarea.js +1 -1
- package/lib/platform/template/wx/component-config/view.js +12 -2
- package/lib/react/index.js +0 -1
- package/lib/react/processJSON.js +13 -2
- package/lib/react/processScript.js +7 -4
- package/lib/react/processTemplate.js +18 -3
- package/lib/react/script-helper.js +18 -4
- package/lib/runtime/components/react/context.ts +3 -4
- package/lib/runtime/components/react/dist/mpx-image.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-input.jsx +54 -54
- package/lib/runtime/components/react/dist/{KeyboardAvoidingView.jsx → mpx-keyboard-avoiding-view.jsx} +23 -12
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +1 -2
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +16 -8
- package/lib/runtime/components/react/dist/mpx-simple-view.jsx +22 -0
- package/lib/runtime/components/react/dist/mpx-textarea.jsx +6 -6
- package/lib/runtime/components/react/dist/mpx-view.jsx +10 -5
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +6 -5
- package/lib/runtime/components/react/dist/useAnimationHooks.js +46 -48
- package/lib/runtime/components/react/dist/utils.jsx +17 -21
- package/lib/runtime/components/react/mpx-image.tsx +2 -2
- package/lib/runtime/components/react/mpx-input.tsx +66 -72
- package/lib/runtime/components/react/{KeyboardAvoidingView.tsx → mpx-keyboard-avoiding-view.tsx} +32 -18
- package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +1 -2
- package/lib/runtime/components/react/mpx-scroll-view.tsx +21 -8
- package/lib/runtime/components/react/mpx-simple-view.tsx +32 -0
- package/lib/runtime/components/react/mpx-textarea.tsx +10 -6
- package/lib/runtime/components/react/mpx-view.tsx +17 -10
- package/lib/runtime/components/react/mpx-web-view.tsx +12 -10
- package/lib/runtime/components/react/types/getInnerListeners.d.ts +1 -1
- package/lib/runtime/components/react/useAnimationHooks.ts +46 -48
- package/lib/runtime/components/react/utils.tsx +21 -24
- package/lib/runtime/optionProcessor.js +3 -2
- package/lib/style-compiler/index.js +8 -6
- package/lib/template-compiler/compiler.js +22 -14
- package/lib/utils/match-condition.js +14 -8
- package/lib/web/processJSON.js +1 -3
- package/package.json +4 -4
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import React, { useContext, useEffect } from 'react';
|
|
1
|
+
import React, { useContext, useEffect, useMemo } from 'react';
|
|
2
2
|
import { Keyboard, Platform, View } from 'react-native';
|
|
3
3
|
import Animated, { useSharedValue, useAnimatedStyle, withTiming, Easing } from 'react-native-reanimated';
|
|
4
|
+
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
|
|
4
5
|
import { KeyboardAvoidContext } from './context';
|
|
5
|
-
import { extendObject } from './utils';
|
|
6
6
|
const KeyboardAvoidingView = ({ children, style, contentContainerStyle }) => {
|
|
7
7
|
const isIOS = Platform.OS === 'ios';
|
|
8
8
|
const duration = isIOS ? 250 : 300;
|
|
@@ -10,16 +10,24 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }) => {
|
|
|
10
10
|
const offset = useSharedValue(0);
|
|
11
11
|
const basic = useSharedValue('auto');
|
|
12
12
|
const keyboardAvoid = useContext(KeyboardAvoidContext);
|
|
13
|
+
const dismiss = () => {
|
|
14
|
+
Keyboard.isVisible() && Keyboard.dismiss();
|
|
15
|
+
};
|
|
16
|
+
const gesture = useMemo(() => {
|
|
17
|
+
return Gesture.Tap()
|
|
18
|
+
.onEnd(() => {
|
|
19
|
+
dismiss();
|
|
20
|
+
}).runOnJS(true);
|
|
21
|
+
}, []);
|
|
13
22
|
const animatedStyle = useAnimatedStyle(() => {
|
|
14
23
|
return Object.assign({
|
|
15
24
|
transform: [{ translateY: -offset.value }]
|
|
16
25
|
}, isIOS ? {} : { flexBasis: basic.value });
|
|
17
26
|
});
|
|
18
27
|
const resetKeyboard = () => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
28
|
+
if (keyboardAvoid?.current) {
|
|
29
|
+
keyboardAvoid.current = null;
|
|
30
|
+
}
|
|
23
31
|
offset.value = withTiming(0, { duration, easing });
|
|
24
32
|
basic.value = 'auto';
|
|
25
33
|
};
|
|
@@ -34,7 +42,7 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }) => {
|
|
|
34
42
|
const { ref, cursorSpacing = 0 } = keyboardAvoid.current;
|
|
35
43
|
setTimeout(() => {
|
|
36
44
|
ref?.current?.measure((x, y, width, height, pageX, pageY) => {
|
|
37
|
-
const aboveOffset =
|
|
45
|
+
const aboveOffset = pageY + height - endCoordinates.screenY;
|
|
38
46
|
const aboveValue = -aboveOffset >= cursorSpacing ? 0 : aboveOffset + cursorSpacing;
|
|
39
47
|
const belowValue = Math.min(endCoordinates.height, aboveOffset + cursorSpacing);
|
|
40
48
|
const value = aboveOffset > 0 ? belowValue : aboveValue;
|
|
@@ -77,13 +85,16 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }) => {
|
|
|
77
85
|
subscriptions.forEach(subscription => subscription.remove());
|
|
78
86
|
};
|
|
79
87
|
}, [keyboardAvoid]);
|
|
80
|
-
return (<
|
|
81
|
-
<
|
|
88
|
+
return (<GestureDetector gesture={gesture}>
|
|
89
|
+
<View style={style}>
|
|
90
|
+
<Animated.View style={[
|
|
82
91
|
contentContainerStyle,
|
|
83
92
|
animatedStyle
|
|
84
93
|
]}>
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
94
|
+
{children}
|
|
95
|
+
</Animated.View>
|
|
96
|
+
</View>
|
|
97
|
+
</GestureDetector>);
|
|
88
98
|
};
|
|
99
|
+
KeyboardAvoidingView.displayName = 'MpxKeyboardAvoidingView';
|
|
89
100
|
export default KeyboardAvoidingView;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useState, useCallback, forwardRef, useImperativeHandle } from 'react';
|
|
2
2
|
import { View, StyleSheet } from 'react-native';
|
|
3
|
-
import { extendObject } from '../utils';
|
|
4
3
|
const _PortalManager = forwardRef((props, ref) => {
|
|
5
4
|
const [state, setState] = useState({
|
|
6
5
|
portals: []
|
|
@@ -14,7 +13,7 @@ const _PortalManager = forwardRef((props, ref) => {
|
|
|
14
13
|
setState((prevState) => ({
|
|
15
14
|
portals: prevState.portals.map((item) => {
|
|
16
15
|
if (item.key === key) {
|
|
17
|
-
return
|
|
16
|
+
return Object.assign({}, item, { children });
|
|
18
17
|
}
|
|
19
18
|
return item;
|
|
20
19
|
})
|
|
@@ -41,7 +41,7 @@ import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren, ext
|
|
|
41
41
|
import { IntersectionObserverContext, ScrollViewContext } from './context';
|
|
42
42
|
const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
43
43
|
const { textProps, innerProps: props = {} } = splitProps(scrollViewProps);
|
|
44
|
-
const { enhanced = false, bounces = true, style = {}, binddragstart, binddragging, binddragend, bindtouchstart, bindtouchmove, bindtouchend, 'scroll-x': scrollX = false, 'scroll-y': scrollY = false, 'enable-back-to-top': enableBackToTop = false, 'enable-trigger-intersection-observer': enableTriggerIntersectionObserver = false, 'paging-enabled': pagingEnabled = false, 'upper-threshold': upperThreshold = 50, 'lower-threshold': lowerThreshold = 50, 'scroll-with-animation': scrollWithAnimation, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'show-scrollbar': showScrollbar = true, 'scroll-into-view': scrollIntoView = '', 'scroll-top': scrollTop = 0, 'scroll-left': scrollLeft = 0, 'refresher-triggered': refresherTriggered, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'simultaneous-handlers': originSimultaneousHandlers, 'wait-for': waitFor, __selectRef } = props;
|
|
44
|
+
const { enhanced = false, bounces = true, style = {}, binddragstart, binddragging, binddragend, bindtouchstart, bindtouchmove, bindtouchend, 'scroll-x': scrollX = false, 'scroll-y': scrollY = false, 'enable-back-to-top': enableBackToTop = false, 'enable-trigger-intersection-observer': enableTriggerIntersectionObserver = false, 'paging-enabled': pagingEnabled = false, 'upper-threshold': upperThreshold = 50, 'lower-threshold': lowerThreshold = 50, 'scroll-with-animation': scrollWithAnimation = false, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'show-scrollbar': showScrollbar = true, 'scroll-into-view': scrollIntoView = '', 'scroll-top': scrollTop = 0, 'scroll-left': scrollLeft = 0, 'refresher-triggered': refresherTriggered, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'simultaneous-handlers': originSimultaneousHandlers, 'wait-for': waitFor, 'scroll-event-throttle': scrollEventThrottle = 0, __selectRef } = props;
|
|
45
45
|
const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
|
|
46
46
|
const waitForHandlers = flatGesture(waitFor);
|
|
47
47
|
const [refreshing, setRefreshing] = useState(true);
|
|
@@ -54,7 +54,6 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
54
54
|
scrollTop: 0,
|
|
55
55
|
visibleLength: 0
|
|
56
56
|
});
|
|
57
|
-
const scrollEventThrottle = 50;
|
|
58
57
|
const hasCallScrollToUpper = useRef(true);
|
|
59
58
|
const hasCallScrollToLower = useRef(false);
|
|
60
59
|
const initialTimeout = useRef(null);
|
|
@@ -73,7 +72,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
73
72
|
pagingEnabled,
|
|
74
73
|
fastDeceleration: false,
|
|
75
74
|
decelerationDisabled: false,
|
|
76
|
-
scrollTo
|
|
75
|
+
scrollTo
|
|
77
76
|
},
|
|
78
77
|
gestureRef: scrollViewRef
|
|
79
78
|
});
|
|
@@ -83,6 +82,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
83
82
|
};
|
|
84
83
|
}, []);
|
|
85
84
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout });
|
|
85
|
+
const lastOffset = useRef(0);
|
|
86
86
|
if (scrollX && scrollY) {
|
|
87
87
|
warn('scroll-x and scroll-y cannot be set to true at the same time, Mpx will use the value of scroll-y as the criterion');
|
|
88
88
|
}
|
|
@@ -112,6 +112,9 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
112
112
|
}
|
|
113
113
|
firstScrollIntoViewChange.current = true;
|
|
114
114
|
}, [scrollIntoView]);
|
|
115
|
+
function scrollTo({ top = 0, left = 0, animated = false }) {
|
|
116
|
+
scrollToOffset(left, top, animated);
|
|
117
|
+
}
|
|
115
118
|
function handleScrollIntoView() {
|
|
116
119
|
const refs = __selectRef(`#${scrollIntoView}`, 'node');
|
|
117
120
|
if (!refs)
|
|
@@ -130,7 +133,8 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
130
133
|
function onStartReached(e) {
|
|
131
134
|
const { bindscrolltoupper } = props;
|
|
132
135
|
const { offset } = scrollOptions.current;
|
|
133
|
-
|
|
136
|
+
const isScrollingBackward = offset < lastOffset.current;
|
|
137
|
+
if (bindscrolltoupper && (offset <= upperThreshold) && isScrollingBackward) {
|
|
134
138
|
if (!hasCallScrollToUpper.current) {
|
|
135
139
|
bindscrolltoupper(getCustomEvent('scrolltoupper', e, {
|
|
136
140
|
detail: {
|
|
@@ -149,12 +153,13 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
149
153
|
const { bindscrolltolower } = props;
|
|
150
154
|
const { contentLength, visibleLength, offset } = scrollOptions.current;
|
|
151
155
|
const distanceFromEnd = contentLength - visibleLength - offset;
|
|
152
|
-
|
|
156
|
+
const isScrollingForward = offset > lastOffset.current;
|
|
157
|
+
if (bindscrolltolower && (distanceFromEnd < lowerThreshold) && isScrollingForward) {
|
|
153
158
|
if (!hasCallScrollToLower.current) {
|
|
154
159
|
hasCallScrollToLower.current = true;
|
|
155
160
|
bindscrolltolower(getCustomEvent('scrolltolower', e, {
|
|
156
161
|
detail: {
|
|
157
|
-
direction: scrollX ? 'right' : '
|
|
162
|
+
direction: scrollX ? 'right' : 'bottom'
|
|
158
163
|
},
|
|
159
164
|
layoutRef
|
|
160
165
|
}, props));
|
|
@@ -203,6 +208,8 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
203
208
|
onStartReached(e);
|
|
204
209
|
onEndReached(e);
|
|
205
210
|
updateIntersection();
|
|
211
|
+
// 在 onStartReached、onEndReached 执行完后更新 lastOffset
|
|
212
|
+
lastOffset.current = scrollOptions.current.offset;
|
|
206
213
|
}
|
|
207
214
|
function onScrollEnd(e) {
|
|
208
215
|
const { bindscrollend } = props;
|
|
@@ -222,6 +229,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
222
229
|
onStartReached(e);
|
|
223
230
|
onEndReached(e);
|
|
224
231
|
updateIntersection();
|
|
232
|
+
lastOffset.current = scrollOptions.current.offset;
|
|
225
233
|
}
|
|
226
234
|
function updateIntersection() {
|
|
227
235
|
if (enableTriggerIntersectionObserver && intersectionObservers) {
|
|
@@ -230,9 +238,9 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
|
|
|
230
238
|
}
|
|
231
239
|
}
|
|
232
240
|
}
|
|
233
|
-
function scrollToOffset(x = 0, y = 0) {
|
|
241
|
+
function scrollToOffset(x = 0, y = 0, animated = scrollWithAnimation) {
|
|
234
242
|
if (scrollViewRef.current) {
|
|
235
|
-
scrollViewRef.current.scrollTo({ x, y, animated
|
|
243
|
+
scrollViewRef.current.scrollTo({ x, y, animated });
|
|
236
244
|
scrollOptions.current.scrollLeft = x;
|
|
237
245
|
scrollOptions.current.scrollTop = y;
|
|
238
246
|
snapScrollLeft.current = x;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { View } from 'react-native';
|
|
2
|
+
import { createElement, forwardRef, useRef } from 'react';
|
|
3
|
+
import useNodesRef from './useNodesRef';
|
|
4
|
+
import { extendObject, splitProps, splitStyle, wrapChildren } from './utils';
|
|
5
|
+
const _View2 = forwardRef((simpleViewProps, ref) => {
|
|
6
|
+
const nodeRef = useRef(null);
|
|
7
|
+
const { textProps, innerProps: props = {} } = splitProps(simpleViewProps);
|
|
8
|
+
const { textStyle, innerStyle = {} } = splitStyle(props.style || {});
|
|
9
|
+
useNodesRef(props, ref, nodeRef, {
|
|
10
|
+
style: innerStyle || {}
|
|
11
|
+
});
|
|
12
|
+
return createElement(View, extendObject({}, props, {
|
|
13
|
+
style: innerStyle,
|
|
14
|
+
ref: nodeRef
|
|
15
|
+
}), wrapChildren(props, {
|
|
16
|
+
hasVarDec: false,
|
|
17
|
+
textStyle: textStyle,
|
|
18
|
+
textProps
|
|
19
|
+
}));
|
|
20
|
+
});
|
|
21
|
+
_View2.displayName = 'MpxSimpleView';
|
|
22
|
+
export default _View2;
|
|
@@ -3,33 +3,33 @@
|
|
|
3
3
|
* Subtraction:
|
|
4
4
|
* type, password, confirm-hold
|
|
5
5
|
* Addition:
|
|
6
|
-
*
|
|
6
|
+
* ✔ confirm-type
|
|
7
7
|
* ✔ auto-height
|
|
8
8
|
* ✘ fixed
|
|
9
9
|
* ✘ show-confirm-bar
|
|
10
10
|
* ✔ bindlinechange: No `heightRpx` info.
|
|
11
11
|
*/
|
|
12
12
|
import { forwardRef, createElement } from 'react';
|
|
13
|
-
import { Keyboard } from 'react-native';
|
|
14
13
|
import Input from './mpx-input';
|
|
15
14
|
import { omit, extendObject } from './utils';
|
|
16
15
|
const DEFAULT_TEXTAREA_WIDTH = 300;
|
|
17
16
|
const DEFAULT_TEXTAREA_HEIGHT = 150;
|
|
18
17
|
const Textarea = forwardRef((props, ref) => {
|
|
19
|
-
const { style = {} } = props;
|
|
18
|
+
const { style = {}, 'confirm-type': confirmType = 'return' } = props;
|
|
20
19
|
const restProps = omit(props, [
|
|
21
20
|
'ref',
|
|
22
21
|
'type',
|
|
23
22
|
'style',
|
|
24
23
|
'password',
|
|
25
24
|
'multiline',
|
|
25
|
+
'confirm-type',
|
|
26
26
|
'confirm-hold'
|
|
27
27
|
]);
|
|
28
28
|
return createElement(Input, extendObject(restProps, {
|
|
29
|
-
ref
|
|
29
|
+
ref,
|
|
30
|
+
confirmType,
|
|
30
31
|
multiline: true,
|
|
31
|
-
|
|
32
|
-
bindblur: () => Keyboard.dismiss(),
|
|
32
|
+
'confirm-type': confirmType,
|
|
33
33
|
style: extendObject({
|
|
34
34
|
width: DEFAULT_TEXTAREA_WIDTH,
|
|
35
35
|
height: DEFAULT_TEXTAREA_HEIGHT
|
|
@@ -14,6 +14,7 @@ import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wra
|
|
|
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';
|
|
17
|
+
import Portal from './mpx-portal';
|
|
17
18
|
const linearMap = new Map([
|
|
18
19
|
['top', 0],
|
|
19
20
|
['bottom', 180],
|
|
@@ -555,7 +556,7 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
555
556
|
const enableHover = !!hoverStyle;
|
|
556
557
|
const { isHover, gesture } = useHover({ enableHover, hoverStartTime, hoverStayTime });
|
|
557
558
|
const styleObj = extendObject({}, defaultStyle, style, isHover ? hoverStyle : {});
|
|
558
|
-
const { normalStyle, hasSelfPercent, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, {
|
|
559
|
+
const { normalStyle, hasSelfPercent, hasPositionFixed, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, {
|
|
559
560
|
enableVar,
|
|
560
561
|
externalVarContext,
|
|
561
562
|
parentFontSize,
|
|
@@ -600,12 +601,16 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
600
601
|
innerStyle,
|
|
601
602
|
enableFastImage
|
|
602
603
|
});
|
|
603
|
-
|
|
604
|
+
let finalComponent = enableStyleAnimation
|
|
604
605
|
? createElement(Animated.View, innerProps, childNode)
|
|
605
606
|
: createElement(View, innerProps, childNode);
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
607
|
+
if (enableHover) {
|
|
608
|
+
finalComponent = createElement(GestureDetector, { gesture: gesture }, finalComponent);
|
|
609
|
+
}
|
|
610
|
+
if (hasPositionFixed) {
|
|
611
|
+
finalComponent = createElement(Portal, null, finalComponent);
|
|
612
|
+
}
|
|
613
|
+
return finalComponent;
|
|
609
614
|
});
|
|
610
615
|
_View.displayName = 'MpxView';
|
|
611
616
|
export default _View;
|
|
@@ -45,7 +45,7 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
45
45
|
button: 'Reload'
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
|
-
const currentErrorText = errorText[mpx.i18n
|
|
48
|
+
const currentErrorText = errorText[mpx.i18n?.locale || 'zh-CN'];
|
|
49
49
|
if (props.style) {
|
|
50
50
|
warn('The web-view component does not support the style prop.');
|
|
51
51
|
}
|
|
@@ -155,8 +155,8 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
155
155
|
switch (type) {
|
|
156
156
|
case 'setTitle':
|
|
157
157
|
{ // case下不允许直接声明,包个块解决该问题
|
|
158
|
-
const title = postData._documentTitle;
|
|
159
|
-
if (title) {
|
|
158
|
+
const title = postData._documentTitle?.trim();
|
|
159
|
+
if (title !== undefined) {
|
|
160
160
|
navigation && navigation.setOptions({ title });
|
|
161
161
|
}
|
|
162
162
|
}
|
|
@@ -252,6 +252,7 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
252
252
|
};
|
|
253
253
|
const onLoadEnd = function (res) {
|
|
254
254
|
if (__mpx_mode__ === 'android') {
|
|
255
|
+
res.persist();
|
|
255
256
|
setTimeout(() => {
|
|
256
257
|
onLoadEndHandle(res);
|
|
257
258
|
}, 0);
|
|
@@ -276,13 +277,13 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
276
277
|
setIsLoaded(false);
|
|
277
278
|
}
|
|
278
279
|
};
|
|
279
|
-
return (<Portal
|
|
280
|
+
return (<Portal>
|
|
280
281
|
{pageLoadErr
|
|
281
282
|
? (<View style={[styles.loadErrorContext, defaultWebViewStyle]}>
|
|
282
283
|
<View style={styles.loadErrorText}><Text style={{ fontSize: 14, color: '#999999' }}>{currentErrorText.text}</Text></View>
|
|
283
284
|
<View style={styles.loadErrorButton} onTouchEnd={_reload}><Text style={{ fontSize: 12, color: '#666666' }}>{currentErrorText.button}</Text></View>
|
|
284
285
|
</View>)
|
|
285
|
-
: (<WebView style={defaultWebViewStyle} source={{ uri: src }} ref={webViewRef} javaScriptEnabled={true} onNavigationStateChange={_changeUrl} onMessage={_message} injectedJavaScript={injectedJavaScript} onLoadProgress={_onLoadProgress} onLoadEnd={onLoadEnd} onHttpError={onHttpError} onError={onError} onLoadStart={onLoadStart} allowsBackForwardNavigationGestures={
|
|
286
|
+
: (<WebView style={defaultWebViewStyle} pointerEvents={isLoaded ? 'auto' : 'none'} source={{ uri: src }} ref={webViewRef} javaScriptEnabled={true} onNavigationStateChange={_changeUrl} onMessage={_message} injectedJavaScript={injectedJavaScript} onLoadProgress={_onLoadProgress} onLoadEnd={onLoadEnd} onHttpError={onHttpError} onError={onError} onLoadStart={onLoadStart} allowsBackForwardNavigationGestures={true}></WebView>)}
|
|
286
287
|
</Portal>);
|
|
287
288
|
});
|
|
288
289
|
_WebView.displayName = 'MpxWebview';
|
|
@@ -1,6 +1,6 @@
|
|
|
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
|
+
import { error, hasOwn } from '@mpxjs/utils';
|
|
4
4
|
// 微信 timingFunction 和 RN Easing 对应关系
|
|
5
5
|
const EasingKey = {
|
|
6
6
|
linear: Easing.linear,
|
|
@@ -14,20 +14,20 @@ const EasingKey = {
|
|
|
14
14
|
const TransformInitial = {
|
|
15
15
|
// matrix: 0,
|
|
16
16
|
// matrix3d: 0,
|
|
17
|
-
rotate: '0deg',
|
|
17
|
+
// rotate: '0deg',
|
|
18
18
|
rotateX: '0deg',
|
|
19
19
|
rotateY: '0deg',
|
|
20
20
|
rotateZ: '0deg',
|
|
21
21
|
// rotate3d:[0,0,0]
|
|
22
|
-
scale: 1,
|
|
22
|
+
// scale: 1,
|
|
23
23
|
// scale3d: [1, 1, 1],
|
|
24
24
|
scaleX: 1,
|
|
25
25
|
scaleY: 1,
|
|
26
26
|
// scaleZ: 1,
|
|
27
|
-
skew: 0,
|
|
27
|
+
// skew: 0,
|
|
28
28
|
skewX: '0deg',
|
|
29
29
|
skewY: '0deg',
|
|
30
|
-
translate: 0,
|
|
30
|
+
// translate: 0,
|
|
31
31
|
// translate3d: 0,
|
|
32
32
|
translateX: 0,
|
|
33
33
|
translateY: 0
|
|
@@ -92,23 +92,23 @@ const parseTransform = (transformStr) => {
|
|
|
92
92
|
case 'skewX':
|
|
93
93
|
case 'skewY':
|
|
94
94
|
case 'perspective':
|
|
95
|
+
// rotate 处理成 rotateZ
|
|
96
|
+
key = key === 'rotate' ? 'rotateZ' : key;
|
|
95
97
|
// 单个值处理
|
|
96
98
|
transform.push({ [key]: global.__formatValue(val) });
|
|
97
99
|
break;
|
|
98
100
|
case 'matrix':
|
|
99
|
-
case 'matrix3d':
|
|
100
101
|
transform.push({ [key]: parseValues(val, ',').map(val => +val) });
|
|
101
102
|
break;
|
|
102
103
|
case 'translate':
|
|
103
104
|
case 'scale':
|
|
104
105
|
case 'skew':
|
|
105
|
-
case 'rotate3d': // x y z angle
|
|
106
106
|
case 'translate3d': // x y 支持 z不支持
|
|
107
107
|
case 'scale3d': // x y 支持 z不支持
|
|
108
108
|
{
|
|
109
109
|
// 2 个以上的值处理
|
|
110
110
|
key = key.replace('3d', '');
|
|
111
|
-
const vals = parseValues(val, ',').splice(0,
|
|
111
|
+
const vals = parseValues(val, ',').splice(0, 3);
|
|
112
112
|
// scale(.5) === scaleX(.5) scaleY(.5)
|
|
113
113
|
if (vals.length === 1 && key === 'scale') {
|
|
114
114
|
vals.push(vals[0]);
|
|
@@ -132,6 +132,13 @@ const formatStyle = (style) => {
|
|
|
132
132
|
transform: parseTransform(style.transform)
|
|
133
133
|
});
|
|
134
134
|
};
|
|
135
|
+
// transform 数组转对象
|
|
136
|
+
function getTransformObj(transforms) {
|
|
137
|
+
'worklet';
|
|
138
|
+
return transforms.reduce((transformObj, item) => {
|
|
139
|
+
return Object.assign(transformObj, item);
|
|
140
|
+
}, {});
|
|
141
|
+
}
|
|
135
142
|
export default function useAnimationHooks(props) {
|
|
136
143
|
const { style = {}, animation, enableAnimation } = props;
|
|
137
144
|
const enableStyleAnimation = enableAnimation || !!animation;
|
|
@@ -150,7 +157,9 @@ export default function useAnimationHooks(props) {
|
|
|
150
157
|
// 记录动画key的style样式值 没有的话设置为false
|
|
151
158
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
152
159
|
const animatedKeys = useRef({});
|
|
153
|
-
//
|
|
160
|
+
// 记录上次style map
|
|
161
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
162
|
+
const lastStyleRef = useRef({});
|
|
154
163
|
// ** 全量 style prop sharedValue
|
|
155
164
|
// 不能做增量的原因:
|
|
156
165
|
// 1 尝试用 useRef,但 useAnimatedStyle 访问后的 ref 不能在增加新的值,被冻结
|
|
@@ -163,6 +172,12 @@ export default function useAnimationHooks(props) {
|
|
|
163
172
|
return valMap;
|
|
164
173
|
}, {});
|
|
165
174
|
}, []);
|
|
175
|
+
// ** style更新同步
|
|
176
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
// style 更新后同步更新 lastStyleRef & shareValMap
|
|
179
|
+
updateStyleVal();
|
|
180
|
+
}, [style]);
|
|
166
181
|
// ** 获取动画样式prop & 驱动动画
|
|
167
182
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
168
183
|
useEffect(() => {
|
|
@@ -175,16 +190,6 @@ export default function useAnimationHooks(props) {
|
|
|
175
190
|
// 驱动动画
|
|
176
191
|
createAnimation(keys);
|
|
177
192
|
}, [id]);
|
|
178
|
-
// 同步style更新
|
|
179
|
-
// useEffect(() => {
|
|
180
|
-
// Object.keys(animatedKeys.current).forEach(key => {
|
|
181
|
-
// const originVal = getOriginalStyleVal(key, isTransform(key))
|
|
182
|
-
// if (originVal && animatedKeys.current[key] !== originVal) {
|
|
183
|
-
// animatedKeys.current[key] = originVal
|
|
184
|
-
// shareValMap[key].value = originVal
|
|
185
|
-
// }
|
|
186
|
-
// })
|
|
187
|
-
// }, [style])
|
|
188
193
|
// ** 清空动画
|
|
189
194
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
190
195
|
useEffect(() => {
|
|
@@ -194,7 +199,7 @@ export default function useAnimationHooks(props) {
|
|
|
194
199
|
});
|
|
195
200
|
};
|
|
196
201
|
}, []);
|
|
197
|
-
// 根据 animation action 创建&驱动动画
|
|
202
|
+
// 根据 animation action 创建&驱动动画
|
|
198
203
|
function createAnimation(animatedKeys = []) {
|
|
199
204
|
const actions = animation?.actions || [];
|
|
200
205
|
const sequence = {};
|
|
@@ -251,6 +256,7 @@ export default function useAnimationHooks(props) {
|
|
|
251
256
|
: withTiming(value, { duration, easing });
|
|
252
257
|
return delay ? withDelay(delay, animation) : animation;
|
|
253
258
|
}
|
|
259
|
+
// 获取样式初始值(prop style or 默认值)
|
|
254
260
|
function getInitialVal(key, isTransform = false) {
|
|
255
261
|
if (isTransform && Array.isArray(originalStyle.transform)) {
|
|
256
262
|
let initialVal = InitialValue[key];
|
|
@@ -263,31 +269,12 @@ export default function useAnimationHooks(props) {
|
|
|
263
269
|
}
|
|
264
270
|
return originalStyle[key] === undefined ? InitialValue[key] : originalStyle[key];
|
|
265
271
|
}
|
|
266
|
-
// 从 prop style 中获取样式初始值 没有为undefined
|
|
267
|
-
// function getOriginalStyleVal (key: keyof ExtendedViewStyle, isTransform = false) {
|
|
268
|
-
// if (isTransform && Array.isArray(originalStyle.transform)) {
|
|
269
|
-
// let initialVal = undefined // InitialValue[key]
|
|
270
|
-
// // 仅支持 { transform: [{rotateX: '45deg'}, {rotateZ: '0.785398rad'}] } 格式的初始样式
|
|
271
|
-
// originalStyle.transform.forEach(item => {
|
|
272
|
-
// if (item[key] !== undefined) initialVal = item[key]
|
|
273
|
-
// })
|
|
274
|
-
// return initialVal
|
|
275
|
-
// }
|
|
276
|
-
// return originalStyle[key] // === undefined ? InitialValue[key] : originalStyle[key]
|
|
277
|
-
// }
|
|
278
|
-
// 获取动画shareVal初始值(prop style or 默认值)
|
|
279
|
-
// function getInitialVal (key: keyof ExtendedViewStyle, isTransform = false) {
|
|
280
|
-
// const originalVal = getOriginalStyleVal(key, isTransform)
|
|
281
|
-
// return originalVal === undefined ? InitialValue[key] : originalStyle[key]
|
|
282
|
-
// }
|
|
283
272
|
// 循环 animation actions 获取所有有动画的 style prop name
|
|
284
273
|
function getAnimatedStyleKeys() {
|
|
285
274
|
return (animation?.actions || []).reduce((keyMap, action) => {
|
|
286
275
|
const { rules, transform } = action;
|
|
287
276
|
const ruleArr = [...rules.keys(), ...transform.keys()];
|
|
288
277
|
ruleArr.forEach(key => {
|
|
289
|
-
// const originalVal = getOriginalStyleVal(key, isTransform(key))
|
|
290
|
-
// if (!keyMap[key]) keyMap[key] = originalVal === undefined ? false : originalVal
|
|
291
278
|
if (!keyMap[key])
|
|
292
279
|
keyMap[key] = true;
|
|
293
280
|
});
|
|
@@ -295,7 +282,7 @@ export default function useAnimationHooks(props) {
|
|
|
295
282
|
}, animatedKeys.current);
|
|
296
283
|
}
|
|
297
284
|
// animated key transform 格式化
|
|
298
|
-
function formatAnimatedKeys(keys
|
|
285
|
+
function formatAnimatedKeys(keys) {
|
|
299
286
|
const animatedKeys = [];
|
|
300
287
|
const transforms = [];
|
|
301
288
|
keys.forEach(key => {
|
|
@@ -310,13 +297,24 @@ export default function useAnimationHooks(props) {
|
|
|
310
297
|
animatedKeys.push(transforms);
|
|
311
298
|
return animatedKeys;
|
|
312
299
|
}
|
|
313
|
-
//
|
|
314
|
-
function
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
300
|
+
// 设置 lastShareValRef & shareValMap
|
|
301
|
+
function updateStyleVal() {
|
|
302
|
+
Object.entries(originalStyle).forEach(([key, value]) => {
|
|
303
|
+
if (key === 'transform') {
|
|
304
|
+
Object.entries(getTransformObj(value)).forEach(([key, value]) => {
|
|
305
|
+
if (value !== lastStyleRef.current[key]) {
|
|
306
|
+
lastStyleRef.current[key] = value;
|
|
307
|
+
shareValMap[key].value = value;
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
else if (hasOwn(shareValMap, key)) {
|
|
312
|
+
if (value !== lastStyleRef.current[key]) {
|
|
313
|
+
lastStyleRef.current[key] = value;
|
|
314
|
+
shareValMap[key].value = value;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
});
|
|
320
318
|
}
|
|
321
319
|
// ** 生成动画样式
|
|
322
320
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
@@ -325,7 +323,7 @@ export default function useAnimationHooks(props) {
|
|
|
325
323
|
return animatedStyleKeys.value.reduce((styles, key) => {
|
|
326
324
|
// console.info('getAnimationStyles', key, shareValMap[key].value)
|
|
327
325
|
if (Array.isArray(key)) {
|
|
328
|
-
const transformStyle = getTransformObj();
|
|
326
|
+
const transformStyle = getTransformObj(originalStyle.transform || []);
|
|
329
327
|
key.forEach((transformKey) => {
|
|
330
328
|
transformStyle[transformKey] = shareValMap[transformKey].value;
|
|
331
329
|
});
|
|
@@ -67,20 +67,6 @@ export const useUpdateEffect = (effect, deps) => {
|
|
|
67
67
|
}
|
|
68
68
|
}, deps);
|
|
69
69
|
};
|
|
70
|
-
/**
|
|
71
|
-
* 解析行内样式
|
|
72
|
-
* @param inlineStyle
|
|
73
|
-
* @returns
|
|
74
|
-
*/
|
|
75
|
-
export const parseInlineStyle = (inlineStyle = '') => {
|
|
76
|
-
return inlineStyle.split(';').reduce((styleObj, style) => {
|
|
77
|
-
const [k, v, ...rest] = style.split(':');
|
|
78
|
-
if (rest.length || !v || !k)
|
|
79
|
-
return styleObj;
|
|
80
|
-
const key = k.trim().replace(/-./g, c => c.substring(1).toUpperCase());
|
|
81
|
-
return extendObject(styleObj, { [key]: global.__formatValue(v.trim()) });
|
|
82
|
-
}, {});
|
|
83
|
-
};
|
|
84
70
|
export const parseUrl = (cssUrl = '') => {
|
|
85
71
|
if (!cssUrl)
|
|
86
72
|
return;
|
|
@@ -253,12 +239,8 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
|
|
|
253
239
|
const normalStyleChangedRef = useRef(false);
|
|
254
240
|
let hasVarDec = false;
|
|
255
241
|
let hasVarUse = false;
|
|
256
|
-
let hasSelfPercent = false;
|
|
257
242
|
const varKeyPaths = [];
|
|
258
243
|
const unoVarKeyPaths = [];
|
|
259
|
-
const percentKeyPaths = [];
|
|
260
|
-
const calcKeyPaths = [];
|
|
261
|
-
const envKeyPaths = [];
|
|
262
244
|
const [width, setWidth] = useState(0);
|
|
263
245
|
const [height, setHeight] = useState(0);
|
|
264
246
|
const navigation = useNavigation();
|
|
@@ -318,6 +300,11 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
|
|
|
318
300
|
normalStyleChangedRef.current = !normalStyleChangedRef.current;
|
|
319
301
|
}
|
|
320
302
|
const memoResult = useMemo(() => {
|
|
303
|
+
let hasSelfPercent = false;
|
|
304
|
+
let hasPositionFixed = false;
|
|
305
|
+
const percentKeyPaths = [];
|
|
306
|
+
const calcKeyPaths = [];
|
|
307
|
+
const envKeyPaths = [];
|
|
321
308
|
// transform can be memoized
|
|
322
309
|
function envVisitor({ value, keyPath }) {
|
|
323
310
|
if (envUseRegExp.test(value)) {
|
|
@@ -338,6 +325,12 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
|
|
|
338
325
|
percentKeyPaths.push(keyPath.slice());
|
|
339
326
|
}
|
|
340
327
|
}
|
|
328
|
+
function transformPosition(styleObj) {
|
|
329
|
+
if (styleObj.position === 'fixed') {
|
|
330
|
+
hasPositionFixed = true;
|
|
331
|
+
styleObj.position = 'absolute';
|
|
332
|
+
}
|
|
333
|
+
}
|
|
341
334
|
// traverse env & calc & percent
|
|
342
335
|
traverseStyle(normalStyle, [envVisitor, percentVisitor, calcVisitor]);
|
|
343
336
|
const percentConfig = {
|
|
@@ -369,11 +362,14 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
|
|
|
369
362
|
}
|
|
370
363
|
}
|
|
371
364
|
});
|
|
365
|
+
// apply position
|
|
366
|
+
transformPosition(normalStyle);
|
|
372
367
|
// transform number enum stringify
|
|
373
368
|
transformStringify(normalStyle);
|
|
374
369
|
return {
|
|
375
370
|
normalStyle,
|
|
376
|
-
hasSelfPercent
|
|
371
|
+
hasSelfPercent,
|
|
372
|
+
hasPositionFixed
|
|
377
373
|
};
|
|
378
374
|
}, [normalStyleChangedRef.current, width, height, parentWidth, parentHeight, parentFontSize]);
|
|
379
375
|
return extendObject({
|
|
@@ -448,8 +444,8 @@ export const useLayout = ({ props, hasSelfPercent, setWidth, setHeight, onLayout
|
|
|
448
444
|
hasLayoutRef.current = true;
|
|
449
445
|
if (hasSelfPercent) {
|
|
450
446
|
const { width, height } = e?.nativeEvent?.layout || {};
|
|
451
|
-
setWidth(width || 0);
|
|
452
|
-
setHeight(height || 0);
|
|
447
|
+
setWidth && setWidth(width || 0);
|
|
448
|
+
setHeight && setHeight(height || 0);
|
|
453
449
|
}
|
|
454
450
|
if (enableOffset) {
|
|
455
451
|
nodeRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
|
|
@@ -411,7 +411,7 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
|
|
|
411
411
|
onLayout: onSvgLoad,
|
|
412
412
|
onError: binderror && onSvgError,
|
|
413
413
|
style: extendObject(
|
|
414
|
-
{ transformOrigin: 'top
|
|
414
|
+
{ transformOrigin: 'left top' },
|
|
415
415
|
modeStyle
|
|
416
416
|
)
|
|
417
417
|
})
|
|
@@ -426,7 +426,7 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
|
|
|
426
426
|
onError: binderror && onImageError,
|
|
427
427
|
style: extendObject(
|
|
428
428
|
{
|
|
429
|
-
transformOrigin: 'top
|
|
429
|
+
transformOrigin: 'left top',
|
|
430
430
|
width: isCropMode ? imageWidth : '100%',
|
|
431
431
|
height: isCropMode ? imageHeight : '100%'
|
|
432
432
|
},
|