@mpxjs/webpack-plugin 2.10.3-beta.17 → 2.10.3-beta.18
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/dist/context.js +5 -1
- package/lib/runtime/components/react/dist/event.config.js +0 -1
- package/lib/runtime/components/react/dist/getInnerListeners.js +148 -149
- package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +145 -0
- package/lib/runtime/components/react/dist/mpx-button.jsx +11 -7
- package/lib/runtime/components/react/dist/mpx-canvas/Image.js +2 -4
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +23 -21
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +9 -4
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +9 -5
- package/lib/runtime/components/react/dist/mpx-form.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-icon/icons/cancel.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/clear.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/download.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/info.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/search.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/success.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/success_no_circle.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/waiting.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/warn.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/index.jsx +9 -4
- package/lib/runtime/components/react/dist/mpx-image.jsx +92 -41
- package/lib/runtime/components/react/dist/mpx-inline-text.jsx +11 -0
- package/lib/runtime/components/react/dist/mpx-input.jsx +14 -13
- package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +22 -7
- package/lib/runtime/components/react/dist/mpx-label.jsx +9 -5
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +10 -5
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +206 -80
- package/lib/runtime/components/react/dist/mpx-navigator.jsx +11 -3
- package/lib/runtime/components/react/dist/mpx-picker/date.jsx +194 -68
- package/lib/runtime/components/react/dist/mpx-picker/dateData.js +17 -0
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +178 -98
- package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +79 -139
- package/lib/runtime/components/react/dist/mpx-picker/region.jsx +190 -90
- package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +60 -75
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +100 -228
- package/lib/runtime/components/react/dist/{mpx-picker-view.jsx → mpx-picker-view/index.jsx} +16 -15
- package/lib/runtime/components/react/dist/{mpx-picker-view-column.jsx → mpx-picker-view-column/index.jsx} +95 -26
- package/lib/runtime/components/react/dist/{mpx-picker-view-column-item.jsx → mpx-picker-view-column/pickerViewColumnItem.jsx} +16 -16
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItemLite.jsx +20 -0
- package/lib/runtime/components/react/dist/{pickerFaces.js → mpx-picker-view-column/pickerViewFaces.js} +6 -0
- package/lib/runtime/components/react/dist/mpx-popup/index.jsx +61 -0
- package/lib/runtime/components/react/dist/mpx-popup/popupBase.jsx +92 -0
- package/lib/runtime/components/react/dist/mpx-portal/index.jsx +5 -1
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +3 -5
- package/lib/runtime/components/react/dist/mpx-progress.jsx +163 -0
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +11 -4
- package/lib/runtime/components/react/dist/mpx-radio.jsx +9 -5
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +12 -4
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +317 -89
- package/lib/runtime/components/react/dist/mpx-simple-text.jsx +7 -5
- package/lib/runtime/components/react/dist/mpx-simple-view.jsx +11 -15
- package/lib/runtime/components/react/dist/mpx-slider.jsx +321 -0
- package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +117 -0
- package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +45 -0
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +15 -14
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +245 -121
- package/lib/runtime/components/react/dist/mpx-switch.jsx +10 -7
- package/lib/runtime/components/react/dist/mpx-text.jsx +43 -13
- package/lib/runtime/components/react/dist/mpx-video.jsx +12 -7
- package/lib/runtime/components/react/dist/mpx-view.jsx +34 -18
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +40 -35
- package/lib/runtime/components/react/dist/useAnimationHooks.js +35 -90
- package/lib/runtime/components/react/dist/utils.jsx +215 -109
- package/lib/runtime/components/web/mpx-titlebar.vue +21 -18
- package/package.json +1 -1
- /package/lib/runtime/components/react/dist/{pickerVIewContext.js → mpx-picker-view/pickerVIewContext.js} +0 -0
- /package/lib/runtime/components/react/dist/{pickerViewIndicator.jsx → mpx-picker-view-column/pickerViewIndicator.jsx} +0 -0
- /package/lib/runtime/components/react/dist/{pickerViewMask.jsx → mpx-picker-view-column/pickerViewMask.jsx} +0 -0
|
@@ -10,6 +10,7 @@ import { warn } from '@mpxjs/utils';
|
|
|
10
10
|
import useNodesRef from './useNodesRef'; // 引入辅助函数
|
|
11
11
|
import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
12
12
|
import CheckBox from './mpx-checkbox';
|
|
13
|
+
import Portal from './mpx-portal';
|
|
13
14
|
import { FormContext } from './context';
|
|
14
15
|
import { useTransformStyle, useLayout, extendObject } from './utils';
|
|
15
16
|
const _Switch = forwardRef((props, ref) => {
|
|
@@ -21,7 +22,7 @@ const _Switch = forwardRef((props, ref) => {
|
|
|
21
22
|
if (formContext) {
|
|
22
23
|
formValuesMap = formContext.formValuesMap;
|
|
23
24
|
}
|
|
24
|
-
const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, {
|
|
25
|
+
const { normalStyle, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(style, {
|
|
25
26
|
enableVar,
|
|
26
27
|
externalVarContext,
|
|
27
28
|
parentFontSize,
|
|
@@ -67,17 +68,15 @@ const _Switch = forwardRef((props, ref) => {
|
|
|
67
68
|
}
|
|
68
69
|
};
|
|
69
70
|
}, []);
|
|
70
|
-
const innerProps = useInnerProps(props,
|
|
71
|
+
const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
|
|
71
72
|
ref: nodeRef,
|
|
72
73
|
style: extendObject({}, normalStyle, layoutStyle)
|
|
73
|
-
},
|
|
74
|
+
}, !disabled ? { [type === 'switch' ? 'onValueChange' : '_onChange']: onChange } : {}), [
|
|
74
75
|
'checked',
|
|
75
76
|
'disabled',
|
|
76
77
|
'type',
|
|
77
78
|
'color'
|
|
78
|
-
], {
|
|
79
|
-
layoutRef
|
|
80
|
-
});
|
|
79
|
+
], { layoutRef });
|
|
81
80
|
if (type === 'checkbox') {
|
|
82
81
|
return createElement(CheckBox, extendObject({}, innerProps, {
|
|
83
82
|
color: color,
|
|
@@ -85,13 +84,17 @@ const _Switch = forwardRef((props, ref) => {
|
|
|
85
84
|
checked: isChecked
|
|
86
85
|
}));
|
|
87
86
|
}
|
|
88
|
-
|
|
87
|
+
let finalComponent = createElement(Switch, extendObject({}, innerProps, {
|
|
89
88
|
style: normalStyle,
|
|
90
89
|
value: isChecked,
|
|
91
90
|
trackColor: { false: '#FFF', true: color },
|
|
92
91
|
thumbColor: isChecked ? '#FFF' : '#f4f3f4',
|
|
93
92
|
ios_backgroundColor: '#FFF'
|
|
94
93
|
}));
|
|
94
|
+
if (hasPositionFixed) {
|
|
95
|
+
finalComponent = createElement(Portal, null, finalComponent);
|
|
96
|
+
}
|
|
97
|
+
return finalComponent;
|
|
95
98
|
});
|
|
96
99
|
_Switch.displayName = 'MpxSwitch';
|
|
97
100
|
export default _Switch;
|
|
@@ -1,17 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ✔ selectable
|
|
3
3
|
* ✘ space
|
|
4
|
-
*
|
|
4
|
+
* ✔ decode
|
|
5
5
|
*/
|
|
6
6
|
import { Text } from 'react-native';
|
|
7
|
-
import { useRef, forwardRef, createElement } from 'react';
|
|
7
|
+
import { useRef, forwardRef, createElement, Children } from 'react';
|
|
8
|
+
import Portal from './mpx-portal';
|
|
8
9
|
import useInnerProps from './getInnerListeners';
|
|
9
10
|
import useNodesRef from './useNodesRef'; // 引入辅助函数
|
|
10
|
-
import { useTransformStyle, wrapChildren } from './utils';
|
|
11
|
+
import { useTransformStyle, wrapChildren, extendObject } from './utils';
|
|
12
|
+
const decodeMap = {
|
|
13
|
+
'<': '<',
|
|
14
|
+
'>': '>',
|
|
15
|
+
'"': '"',
|
|
16
|
+
'&': '&',
|
|
17
|
+
''': '\'',
|
|
18
|
+
' ': ' '
|
|
19
|
+
};
|
|
20
|
+
const encodedRe = /&(?:lt|gt|quot|amp|#39|nbsp);/g;
|
|
21
|
+
function decode(value) {
|
|
22
|
+
if (value != null) {
|
|
23
|
+
return value.replace(encodedRe, function (match) {
|
|
24
|
+
return decodeMap[match];
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function getDecodedChildren(children) {
|
|
29
|
+
return Children.map(children, (child) => {
|
|
30
|
+
if (typeof child === 'string') {
|
|
31
|
+
return decode(child);
|
|
32
|
+
}
|
|
33
|
+
return child;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
11
36
|
const _Text = forwardRef((props, ref) => {
|
|
12
|
-
const { style = {}, allowFontScaling = false, selectable, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'user-select': userSelect, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
|
|
13
|
-
const
|
|
14
|
-
const { normalStyle, hasVarDec, varContextRef } = useTransformStyle(style, {
|
|
37
|
+
const { style = {}, allowFontScaling = false, selectable, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'user-select': userSelect, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, decode } = props;
|
|
38
|
+
const { normalStyle, hasVarDec, varContextRef, hasPositionFixed } = useTransformStyle(style, {
|
|
15
39
|
enableVar,
|
|
16
40
|
externalVarContext,
|
|
17
41
|
parentFontSize,
|
|
@@ -22,20 +46,26 @@ const _Text = forwardRef((props, ref) => {
|
|
|
22
46
|
useNodesRef(props, ref, nodeRef, {
|
|
23
47
|
style: normalStyle
|
|
24
48
|
});
|
|
25
|
-
const innerProps = useInnerProps(props, {
|
|
49
|
+
const innerProps = useInnerProps(extendObject({}, props, {
|
|
26
50
|
ref: nodeRef,
|
|
27
51
|
style: normalStyle,
|
|
28
52
|
selectable: !!selectable || !!userSelect,
|
|
29
53
|
allowFontScaling
|
|
30
|
-
}, [
|
|
31
|
-
'user-select'
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
54
|
+
}), [
|
|
55
|
+
'user-select',
|
|
56
|
+
'decode'
|
|
57
|
+
]);
|
|
58
|
+
const children = decode ? getDecodedChildren(props.children) : props.children;
|
|
59
|
+
let finalComponent = createElement(Text, innerProps, wrapChildren(extendObject({}, props, {
|
|
60
|
+
children
|
|
61
|
+
}), {
|
|
36
62
|
hasVarDec,
|
|
37
63
|
varContext: varContextRef.current
|
|
38
64
|
}));
|
|
65
|
+
if (hasPositionFixed) {
|
|
66
|
+
finalComponent = createElement(Portal, null, finalComponent);
|
|
67
|
+
}
|
|
68
|
+
return finalComponent;
|
|
39
69
|
});
|
|
40
70
|
_Text.displayName = 'MpxText';
|
|
41
71
|
export default _Text;
|
|
@@ -64,10 +64,11 @@
|
|
|
64
64
|
*/
|
|
65
65
|
import { useRef, forwardRef, createElement } from 'react';
|
|
66
66
|
import Video, { DRMType } from 'react-native-video';
|
|
67
|
-
import { StyleSheet, View
|
|
67
|
+
import { StyleSheet, View } from 'react-native';
|
|
68
68
|
import { splitProps, useTransformStyle, useLayout, extendObject } from './utils';
|
|
69
69
|
import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
70
70
|
import useNodesRef from './useNodesRef';
|
|
71
|
+
import Portal from './mpx-portal';
|
|
71
72
|
const styles = StyleSheet.create({
|
|
72
73
|
container: {
|
|
73
74
|
width: 300,
|
|
@@ -85,7 +86,7 @@ const MpxVideo = forwardRef((videoProps, ref) => {
|
|
|
85
86
|
const videoInfoRef = useRef({});
|
|
86
87
|
const propsRef = useRef({});
|
|
87
88
|
propsRef.current = props;
|
|
88
|
-
const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(extendObject({}, styles.container, style), {
|
|
89
|
+
const { normalStyle, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(extendObject({}, styles.container, style), {
|
|
89
90
|
enableVar,
|
|
90
91
|
externalVarContext,
|
|
91
92
|
parentFontSize,
|
|
@@ -132,7 +133,7 @@ const MpxVideo = forwardRef((videoProps, ref) => {
|
|
|
132
133
|
// 手动拖拽进度条场景,android 可以触发,ios 不可以
|
|
133
134
|
bindseekcomplete(getCustomEvent('seekcomplete', {}, {
|
|
134
135
|
detail: {
|
|
135
|
-
position:
|
|
136
|
+
position: __mpx_mode__ !== 'ios' ? seekTime * 1000 : seekTime
|
|
136
137
|
},
|
|
137
138
|
layoutRef
|
|
138
139
|
}, propsRef.current));
|
|
@@ -202,11 +203,11 @@ const MpxVideo = forwardRef((videoProps, ref) => {
|
|
|
202
203
|
if (isDrm) {
|
|
203
204
|
source.drm = {
|
|
204
205
|
type: DRMType.FAIRPLAY,
|
|
205
|
-
certificateUrl:
|
|
206
|
+
certificateUrl: __mpx_mode__ !== 'ios' ? provisionUrl : certificateUrl,
|
|
206
207
|
licenseServer: licenseUrl
|
|
207
208
|
};
|
|
208
209
|
}
|
|
209
|
-
const innerProps = useInnerProps(props,
|
|
210
|
+
const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
|
|
210
211
|
style: styles.video,
|
|
211
212
|
ref: videoRef,
|
|
212
213
|
source,
|
|
@@ -228,7 +229,7 @@ const MpxVideo = forwardRef((videoProps, ref) => {
|
|
|
228
229
|
onFullscreenPlayerWillDismiss: bindfullscreenchange && handleExitFullScreen,
|
|
229
230
|
onControlsVisibilityChange: bindcontrolstoggle && handleAndroidControlsVisibilityChange,
|
|
230
231
|
onLoad: handleVideoLoad
|
|
231
|
-
}
|
|
232
|
+
}), [
|
|
232
233
|
'src',
|
|
233
234
|
'autoplay',
|
|
234
235
|
'loop',
|
|
@@ -243,6 +244,10 @@ const MpxVideo = forwardRef((videoProps, ref) => {
|
|
|
243
244
|
'bindcontrolstoggle',
|
|
244
245
|
'bindseekcomplete'
|
|
245
246
|
], { layoutRef });
|
|
246
|
-
|
|
247
|
+
let videoComponent = createElement(View, { style: extendObject({}, normalStyle, layoutStyle), ref: viewRef }, createElement(Video, innerProps));
|
|
248
|
+
if (hasPositionFixed) {
|
|
249
|
+
videoComponent = createElement(Portal, null, videoComponent);
|
|
250
|
+
}
|
|
251
|
+
return videoComponent;
|
|
247
252
|
});
|
|
248
253
|
export default MpxVideo;
|
|
@@ -11,7 +11,7 @@ import Animated from 'react-native-reanimated';
|
|
|
11
11
|
import useAnimationHooks from './useAnimationHooks';
|
|
12
12
|
import useNodesRef from './useNodesRef';
|
|
13
13
|
import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout, renderImage, pickStyle, extendObject, useHover } from './utils';
|
|
14
|
-
import { error } from '@mpxjs/utils';
|
|
14
|
+
import { error, isFunction } from '@mpxjs/utils';
|
|
15
15
|
import LinearGradient from 'react-native-linear-gradient';
|
|
16
16
|
import { GestureDetector } from 'react-native-gesture-handler';
|
|
17
17
|
import Portal from './mpx-portal';
|
|
@@ -57,7 +57,7 @@ const normalizeStyle = (style = {}) => {
|
|
|
57
57
|
const isPercent = (val) => typeof val === 'string' && PERCENT_REGEX.test(val);
|
|
58
58
|
const isBackgroundSizeKeyword = (val) => typeof val === 'string' && /^cover|contain$/.test(val);
|
|
59
59
|
const isNeedLayout = (preImageInfo) => {
|
|
60
|
-
const { sizeList, backgroundPosition, linearInfo } = preImageInfo;
|
|
60
|
+
const { sizeList, backgroundPosition, linearInfo, type } = preImageInfo;
|
|
61
61
|
const [width, height] = sizeList;
|
|
62
62
|
const bp = backgroundPosition;
|
|
63
63
|
// 含有百分号,center 需计算布局
|
|
@@ -66,7 +66,8 @@ const isNeedLayout = (preImageInfo) => {
|
|
|
66
66
|
(isPercent(width) && height === 'auto') ||
|
|
67
67
|
isPercent(bp[1]) ||
|
|
68
68
|
isPercent(bp[3]) ||
|
|
69
|
-
isDiagonalAngle(linearInfo)
|
|
69
|
+
isDiagonalAngle(linearInfo) ||
|
|
70
|
+
(type === 'linear' && (isPercent(height) || isPercent(width)));
|
|
70
71
|
};
|
|
71
72
|
const checkNeedLayout = (preImageInfo) => {
|
|
72
73
|
const { sizeList } = preImageInfo;
|
|
@@ -155,7 +156,7 @@ function backgroundPosition(imageProps, preImageInfo, imageSize, layoutInfo) {
|
|
|
155
156
|
}
|
|
156
157
|
// background-size 转换
|
|
157
158
|
function backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo) {
|
|
158
|
-
const sizeList = preImageInfo
|
|
159
|
+
const { sizeList, type } = preImageInfo;
|
|
159
160
|
if (!sizeList)
|
|
160
161
|
return;
|
|
161
162
|
const { width: layoutWidth, height: layoutHeight } = layoutInfo || {};
|
|
@@ -202,10 +203,20 @@ function backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo) {
|
|
|
202
203
|
else { // 数值类型 ImageStyle
|
|
203
204
|
// 数值类型设置为 stretch
|
|
204
205
|
imageProps.resizeMode = 'stretch';
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
206
|
+
if (type === 'linear' && (!layoutWidth || !layoutHeight)) {
|
|
207
|
+
// ios 上 linear 组件只要重新触发渲染,在渲染过程中外层容器 width 或者 height 被设置为 0,通过设置 % 的方式会渲染不出来,即使后面再更新为正常宽高也渲染不出来
|
|
208
|
+
// 所以 hack 手动先将 linear 宽高也设置为 0,后面再更新为正确的数值或 %。
|
|
209
|
+
dimensions = {
|
|
210
|
+
width: 0,
|
|
211
|
+
height: 0
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
dimensions = {
|
|
216
|
+
width: isPercent(width) ? width : +width,
|
|
217
|
+
height: isPercent(height) ? height : +height
|
|
218
|
+
};
|
|
219
|
+
}
|
|
209
220
|
}
|
|
210
221
|
}
|
|
211
222
|
// 样式合并
|
|
@@ -387,7 +398,7 @@ function parseLinearGradient(text) {
|
|
|
387
398
|
});
|
|
388
399
|
}
|
|
389
400
|
function parseBgImage(text) {
|
|
390
|
-
if (!text)
|
|
401
|
+
if (!text || text === 'none')
|
|
391
402
|
return {};
|
|
392
403
|
const src = parseUrl(text);
|
|
393
404
|
if (src)
|
|
@@ -523,10 +534,8 @@ function useWrapImage(imageStyle, innerStyle, enableFastImage) {
|
|
|
523
534
|
setShow(true);
|
|
524
535
|
}
|
|
525
536
|
};
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
{show && type === 'image' && (renderImage(imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current), enableFastImage))}
|
|
529
|
-
</View>;
|
|
537
|
+
const backgroundProps = extendObject({ key: 'backgroundImage' }, needLayout ? { onLayout } : {}, { style: extendObject({}, inheritStyle(innerStyle), StyleSheet.absoluteFillObject, { overflow: 'hidden' }) });
|
|
538
|
+
return createElement(View, backgroundProps, show && type === 'linear' && createElement(LinearGradient, extendObject({ useAngle: true }, imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current))), show && type === 'image' && renderImage(imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current), enableFastImage));
|
|
530
539
|
}
|
|
531
540
|
function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps, innerStyle, enableFastImage }) {
|
|
532
541
|
const children = wrapChildren(props, {
|
|
@@ -543,7 +552,7 @@ function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backg
|
|
|
543
552
|
}
|
|
544
553
|
const _View = forwardRef((viewProps, ref) => {
|
|
545
554
|
const { textProps, innerProps: props = {} } = splitProps(viewProps);
|
|
546
|
-
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;
|
|
555
|
+
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, catchtransitionend, bindtransitionend } = props;
|
|
547
556
|
// 默认样式
|
|
548
557
|
const defaultStyle = style.display === 'flex'
|
|
549
558
|
? {
|
|
@@ -575,15 +584,22 @@ const _View = forwardRef((viewProps, ref) => {
|
|
|
575
584
|
});
|
|
576
585
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
|
|
577
586
|
const viewStyle = extendObject({}, innerStyle, layoutStyle);
|
|
587
|
+
const transitionend = isFunction(catchtransitionend)
|
|
588
|
+
? catchtransitionend
|
|
589
|
+
: isFunction(bindtransitionend)
|
|
590
|
+
? bindtransitionend
|
|
591
|
+
: undefined;
|
|
578
592
|
const { enableStyleAnimation, animationStyle } = useAnimationHooks({
|
|
579
|
-
|
|
593
|
+
layoutRef,
|
|
580
594
|
animation,
|
|
581
|
-
|
|
595
|
+
enableAnimation,
|
|
596
|
+
style: viewStyle,
|
|
597
|
+
transitionend
|
|
582
598
|
});
|
|
583
|
-
const innerProps = useInnerProps(props,
|
|
599
|
+
const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
|
|
584
600
|
ref: nodeRef,
|
|
585
601
|
style: enableStyleAnimation ? [viewStyle, animationStyle] : viewStyle
|
|
586
|
-
}
|
|
602
|
+
}), [
|
|
587
603
|
'hover-start-time',
|
|
588
604
|
'hover-stay-time',
|
|
589
605
|
'hover-style',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { forwardRef, useRef, useContext, useMemo, useState
|
|
1
|
+
import { forwardRef, useRef, useContext, useMemo, useState } from 'react';
|
|
2
2
|
import { warn, isFunction } from '@mpxjs/utils';
|
|
3
3
|
import Portal from './mpx-portal/index';
|
|
4
|
+
import { usePreventRemove } from '@react-navigation/native';
|
|
4
5
|
import { getCustomEvent } from './getInnerListeners';
|
|
5
6
|
import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab } from '@mpxjs/api-proxy';
|
|
6
7
|
import { WebView } from 'react-native-webview';
|
|
@@ -55,8 +56,8 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
55
56
|
const webViewRef = useRef(null);
|
|
56
57
|
const fristLoaded = useRef(false);
|
|
57
58
|
const isLoadError = useRef(false);
|
|
59
|
+
const isNavigateBack = useRef(false);
|
|
58
60
|
const statusCode = useRef('');
|
|
59
|
-
const [isLoaded, setIsLoaded] = useState(true);
|
|
60
61
|
const defaultWebViewStyle = {
|
|
61
62
|
position: 'absolute',
|
|
62
63
|
left: 0,
|
|
@@ -64,35 +65,42 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
64
65
|
top: 0,
|
|
65
66
|
bottom: 0
|
|
66
67
|
};
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
const navigation = useNavigation();
|
|
69
|
+
const [isIntercept, setIsIntercept] = useState(false);
|
|
70
|
+
usePreventRemove(isIntercept, (event) => {
|
|
71
|
+
const { data } = event;
|
|
72
|
+
if (isNavigateBack.current) {
|
|
73
|
+
navigation?.dispatch(data.action);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
71
76
|
webViewRef.current?.goBack();
|
|
72
|
-
e.preventDefault();
|
|
73
77
|
}
|
|
74
78
|
isNavigateBack.current = false;
|
|
75
|
-
};
|
|
76
|
-
const navigation = useNavigation();
|
|
77
|
-
useEffect(() => {
|
|
78
|
-
let beforeRemoveSubscription;
|
|
79
|
-
if (__mpx_mode__ !== 'ios') {
|
|
80
|
-
beforeRemoveSubscription = navigation?.addListener?.('beforeRemove', beforeRemoveHandle);
|
|
81
|
-
}
|
|
82
|
-
return () => {
|
|
83
|
-
if (isFunction(beforeRemoveSubscription)) {
|
|
84
|
-
beforeRemoveSubscription();
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
}, []);
|
|
79
|
+
});
|
|
88
80
|
useNodesRef(props, ref, webViewRef, {
|
|
89
81
|
style: defaultWebViewStyle
|
|
90
82
|
});
|
|
83
|
+
const hostValidate = (url) => {
|
|
84
|
+
const host = url && new URL(url).host;
|
|
85
|
+
const hostWhitelists = mpx.config.rnConfig?.webviewConfig?.hostWhitelists || [];
|
|
86
|
+
if (hostWhitelists.length) {
|
|
87
|
+
return hostWhitelists.some((item) => {
|
|
88
|
+
return host.endsWith(item);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
91
95
|
if (!src) {
|
|
92
96
|
return null;
|
|
93
97
|
}
|
|
98
|
+
if (!hostValidate(src)) {
|
|
99
|
+
console.error('访问页面域名不符合domainWhiteLists白名单配置,请确认是否正确配置该域名白名单');
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
94
102
|
const _reload = function () {
|
|
95
|
-
if (__mpx_mode__
|
|
103
|
+
if (__mpx_mode__ !== 'ios') {
|
|
96
104
|
fristLoaded.current = false; // 安卓需要重新设置
|
|
97
105
|
}
|
|
98
106
|
setPageLoadErr(false);
|
|
@@ -131,16 +139,19 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
131
139
|
};
|
|
132
140
|
const _changeUrl = function (navState) {
|
|
133
141
|
if (navState.navigationType) { // navigationType这个事件在页面开始加载时和页面加载完成时都会被触发所以判断这个避免其他无效触发执行该逻辑
|
|
134
|
-
canGoBack.current = navState.canGoBack;
|
|
135
142
|
currentPage.__webViewUrl = navState.url;
|
|
143
|
+
setIsIntercept(navState.canGoBack);
|
|
136
144
|
}
|
|
137
145
|
};
|
|
138
146
|
const _onLoadProgress = function (event) {
|
|
139
|
-
if (__mpx_mode__
|
|
140
|
-
|
|
147
|
+
if (__mpx_mode__ !== 'ios') {
|
|
148
|
+
setIsIntercept(event.nativeEvent.canGoBack);
|
|
141
149
|
}
|
|
142
150
|
};
|
|
143
151
|
const _message = function (res) {
|
|
152
|
+
if (!hostValidate(res.nativeEvent?.url)) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
144
155
|
let data = {};
|
|
145
156
|
let asyncCallback;
|
|
146
157
|
const navObj = promisify({ redirectTo, navigateTo, navigateBack, reLaunch, switchTab });
|
|
@@ -160,7 +171,7 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
160
171
|
{ // case下不允许直接声明,包个块解决该问题
|
|
161
172
|
const title = postData._documentTitle?.trim();
|
|
162
173
|
if (title !== undefined) {
|
|
163
|
-
navigation && navigation.
|
|
174
|
+
navigation && navigation.setPageConfig({ navigationBarTitleText: title });
|
|
164
175
|
}
|
|
165
176
|
}
|
|
166
177
|
break;
|
|
@@ -192,7 +203,7 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
192
203
|
break;
|
|
193
204
|
default:
|
|
194
205
|
if (type) {
|
|
195
|
-
const implement = mpx.config.webviewConfig.apiImplementations && mpx.config.webviewConfig.apiImplementations[type];
|
|
206
|
+
const implement = mpx.config.rnConfig.webviewConfig && mpx.config.rnConfig.webviewConfig.apiImplementations && mpx.config.rnConfig.webviewConfig.apiImplementations[type];
|
|
196
207
|
if (isFunction(implement)) {
|
|
197
208
|
asyncCallback = Promise.resolve(implement(...params));
|
|
198
209
|
}
|
|
@@ -227,7 +238,6 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
227
238
|
};
|
|
228
239
|
const onLoadEndHandle = function (res) {
|
|
229
240
|
fristLoaded.current = true;
|
|
230
|
-
setIsLoaded(true);
|
|
231
241
|
const src = res.nativeEvent?.url;
|
|
232
242
|
if (isLoadError.current) {
|
|
233
243
|
isLoadError.current = false;
|
|
@@ -254,8 +264,8 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
254
264
|
}
|
|
255
265
|
};
|
|
256
266
|
const onLoadEnd = function (res) {
|
|
257
|
-
|
|
258
|
-
|
|
267
|
+
if (__mpx_mode__ !== 'ios') {
|
|
268
|
+
res.persist();
|
|
259
269
|
setTimeout(() => {
|
|
260
270
|
onLoadEndHandle(res);
|
|
261
271
|
}, 0);
|
|
@@ -275,18 +285,13 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
275
285
|
setPageLoadErr(true);
|
|
276
286
|
}
|
|
277
287
|
};
|
|
278
|
-
const onLoadStart = function () {
|
|
279
|
-
if (!fristLoaded.current) {
|
|
280
|
-
setIsLoaded(false);
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
288
|
return (<Portal>
|
|
284
289
|
{pageLoadErr
|
|
285
290
|
? (<View style={[styles.loadErrorContext, defaultWebViewStyle]}>
|
|
286
291
|
<View style={styles.loadErrorText}><Text style={{ fontSize: 14, color: '#999999' }}>{currentErrorText.text}</Text></View>
|
|
287
292
|
<View style={styles.loadErrorButton} onTouchEnd={_reload}><Text style={{ fontSize: 12, color: '#666666' }}>{currentErrorText.button}</Text></View>
|
|
288
293
|
</View>)
|
|
289
|
-
: (<WebView style={defaultWebViewStyle}
|
|
294
|
+
: (<WebView style={defaultWebViewStyle} source={{ uri: src }} ref={webViewRef} javaScriptEnabled={true} onNavigationStateChange={_changeUrl} onMessage={_message} injectedJavaScript={injectedJavaScript} onLoadProgress={_onLoadProgress} onLoadEnd={onLoadEnd} onHttpError={onHttpError} onError={onError} allowsBackForwardNavigationGestures={true}></WebView>)}
|
|
290
295
|
</Portal>);
|
|
291
296
|
});
|
|
292
297
|
_WebView.displayName = 'MpxWebview';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef } from 'react';
|
|
2
|
-
import { Easing, useSharedValue, withTiming, useAnimatedStyle, withSequence, withDelay, makeMutable, cancelAnimation } from 'react-native-reanimated';
|
|
3
|
-
import { error, hasOwn } from '@mpxjs/utils';
|
|
2
|
+
import { Easing, useSharedValue, withTiming, useAnimatedStyle, withSequence, withDelay, makeMutable, cancelAnimation, runOnJS } from 'react-native-reanimated';
|
|
3
|
+
import { error, hasOwn, collectDataset } from '@mpxjs/utils';
|
|
4
|
+
import { useRunOnJSCallback } from './utils';
|
|
4
5
|
// 微信 timingFunction 和 RN Easing 对应关系
|
|
5
6
|
const EasingKey = {
|
|
6
7
|
linear: Easing.linear,
|
|
@@ -48,90 +49,6 @@ const InitialValue = Object.assign({
|
|
|
48
49
|
const TransformOrigin = 'transformOrigin';
|
|
49
50
|
// transform
|
|
50
51
|
const isTransform = (key) => Object.keys(TransformInitial).includes(key);
|
|
51
|
-
// 多value解析
|
|
52
|
-
const parseValues = (str, char = ' ') => {
|
|
53
|
-
let stack = 0;
|
|
54
|
-
let temp = '';
|
|
55
|
-
const result = [];
|
|
56
|
-
for (let i = 0; i < str.length; i++) {
|
|
57
|
-
if (str[i] === '(') {
|
|
58
|
-
stack++;
|
|
59
|
-
}
|
|
60
|
-
else if (str[i] === ')') {
|
|
61
|
-
stack--;
|
|
62
|
-
}
|
|
63
|
-
// 非括号内 或者 非分隔字符且非空
|
|
64
|
-
if (stack !== 0 || (str[i] !== char && str[i] !== ' ')) {
|
|
65
|
-
temp += str[i];
|
|
66
|
-
}
|
|
67
|
-
if ((stack === 0 && str[i] === char) || i === str.length - 1) {
|
|
68
|
-
result.push(temp);
|
|
69
|
-
temp = '';
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return result;
|
|
73
|
-
};
|
|
74
|
-
// parse string transform, eg: transform: 'rotateX(45deg) rotateZ(0.785398rad)'
|
|
75
|
-
const parseTransform = (transformStr) => {
|
|
76
|
-
const values = parseValues(transformStr);
|
|
77
|
-
const transform = [];
|
|
78
|
-
values.forEach(item => {
|
|
79
|
-
const match = item.match(/([/\w]+)\((.+)\)/);
|
|
80
|
-
if (match && match.length >= 3) {
|
|
81
|
-
let key = match[1];
|
|
82
|
-
const val = match[2];
|
|
83
|
-
switch (key) {
|
|
84
|
-
case 'translateX':
|
|
85
|
-
case 'translateY':
|
|
86
|
-
case 'scaleX':
|
|
87
|
-
case 'scaleY':
|
|
88
|
-
case 'rotateX':
|
|
89
|
-
case 'rotateY':
|
|
90
|
-
case 'rotateZ':
|
|
91
|
-
case 'rotate':
|
|
92
|
-
case 'skewX':
|
|
93
|
-
case 'skewY':
|
|
94
|
-
case 'perspective':
|
|
95
|
-
// rotate 处理成 rotateZ
|
|
96
|
-
key = key === 'rotate' ? 'rotateZ' : key;
|
|
97
|
-
// 单个值处理
|
|
98
|
-
transform.push({ [key]: global.__formatValue(val) });
|
|
99
|
-
break;
|
|
100
|
-
case 'matrix':
|
|
101
|
-
transform.push({ [key]: parseValues(val, ',').map(val => +val) });
|
|
102
|
-
break;
|
|
103
|
-
case 'translate':
|
|
104
|
-
case 'scale':
|
|
105
|
-
case 'skew':
|
|
106
|
-
case 'translate3d': // x y 支持 z不支持
|
|
107
|
-
case 'scale3d': // x y 支持 z不支持
|
|
108
|
-
{
|
|
109
|
-
// 2 个以上的值处理
|
|
110
|
-
key = key.replace('3d', '');
|
|
111
|
-
const vals = parseValues(val, ',').splice(0, 3);
|
|
112
|
-
// scale(.5) === scaleX(.5) scaleY(.5)
|
|
113
|
-
if (vals.length === 1 && key === 'scale') {
|
|
114
|
-
vals.push(vals[0]);
|
|
115
|
-
}
|
|
116
|
-
const xyz = ['X', 'Y', 'Z'];
|
|
117
|
-
transform.push(...vals.map((v, index) => {
|
|
118
|
-
return { [`${key}${xyz[index] || ''}`]: global.__formatValue(v.trim()) };
|
|
119
|
-
}));
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
return transform;
|
|
126
|
-
};
|
|
127
|
-
// format style
|
|
128
|
-
const formatStyle = (style) => {
|
|
129
|
-
if (!style.transform || Array.isArray(style.transform))
|
|
130
|
-
return style;
|
|
131
|
-
return Object.assign({}, style, {
|
|
132
|
-
transform: parseTransform(style.transform)
|
|
133
|
-
});
|
|
134
|
-
};
|
|
135
52
|
// transform 数组转对象
|
|
136
53
|
function getTransformObj(transforms) {
|
|
137
54
|
'worklet';
|
|
@@ -140,7 +57,7 @@ function getTransformObj(transforms) {
|
|
|
140
57
|
}, {});
|
|
141
58
|
}
|
|
142
59
|
export default function useAnimationHooks(props) {
|
|
143
|
-
const { style = {}, animation, enableAnimation } = props;
|
|
60
|
+
const { style: originalStyle = {}, animation, enableAnimation, transitionend, layoutRef } = props;
|
|
144
61
|
const enableStyleAnimation = enableAnimation || !!animation;
|
|
145
62
|
const enableAnimationRef = useRef(enableStyleAnimation);
|
|
146
63
|
if (enableAnimationRef.current !== enableStyleAnimation) {
|
|
@@ -148,7 +65,6 @@ export default function useAnimationHooks(props) {
|
|
|
148
65
|
}
|
|
149
66
|
if (!enableAnimationRef.current)
|
|
150
67
|
return { enableStyleAnimation: false };
|
|
151
|
-
const originalStyle = formatStyle(style);
|
|
152
68
|
// id 标识
|
|
153
69
|
const id = animation?.id || -1;
|
|
154
70
|
// 有动画样式的 style key
|
|
@@ -177,7 +93,7 @@ export default function useAnimationHooks(props) {
|
|
|
177
93
|
useEffect(() => {
|
|
178
94
|
// style 更新后同步更新 lastStyleRef & shareValMap
|
|
179
95
|
updateStyleVal();
|
|
180
|
-
}, [
|
|
96
|
+
}, [originalStyle]);
|
|
181
97
|
// ** 获取动画样式prop & 驱动动画
|
|
182
98
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
183
99
|
useEffect(() => {
|
|
@@ -249,10 +165,39 @@ export default function useAnimationHooks(props) {
|
|
|
249
165
|
});
|
|
250
166
|
});
|
|
251
167
|
}
|
|
168
|
+
function withTimingCallback(finished, current, duration) {
|
|
169
|
+
if (!transitionend)
|
|
170
|
+
return;
|
|
171
|
+
const target = {
|
|
172
|
+
id: animation?.id || -1,
|
|
173
|
+
dataset: collectDataset(props),
|
|
174
|
+
offsetLeft: layoutRef?.current?.offsetLeft || 0,
|
|
175
|
+
offsetTop: layoutRef?.current?.offsetTop || 0
|
|
176
|
+
};
|
|
177
|
+
transitionend({
|
|
178
|
+
type: 'transitionend',
|
|
179
|
+
// elapsedTime 对齐wx 单位s
|
|
180
|
+
detail: { elapsedTime: duration ? duration / 1000 : 0, finished, current },
|
|
181
|
+
target,
|
|
182
|
+
currentTarget: target,
|
|
183
|
+
timeStamp: Date.now()
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
187
|
+
const runOnJSCallbackRef = useRef({
|
|
188
|
+
withTimingCallback
|
|
189
|
+
});
|
|
190
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
191
|
+
const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef);
|
|
252
192
|
// 创建单个animation
|
|
253
193
|
function getAnimation({ key, value }, { delay, duration, easing }, callback) {
|
|
254
194
|
const animation = typeof callback === 'function'
|
|
255
|
-
? withTiming(value, { duration, easing },
|
|
195
|
+
? withTiming(value, { duration, easing }, (finished, current) => {
|
|
196
|
+
callback(finished, current);
|
|
197
|
+
if (transitionend && finished) {
|
|
198
|
+
runOnJS(runOnJSCallback)('withTimingCallback', finished, current, duration);
|
|
199
|
+
}
|
|
200
|
+
})
|
|
256
201
|
: withTiming(value, { duration, easing });
|
|
257
202
|
return delay ? withDelay(delay, animation) : animation;
|
|
258
203
|
}
|