@mpxjs/webpack-plugin 2.9.72 → 2.10.0
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/file-loader.js +5 -0
- package/lib/index.js +21 -3
- 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/unsupported.js +1 -1
- package/lib/platform/template/wx/component-config/video.js +28 -1
- package/lib/platform/template/wx/index.js +2 -2
- package/lib/react/processScript.js +6 -4
- package/lib/react/processTemplate.js +5 -3
- package/lib/runtime/components/react/KeyboardAvoidingView.tsx +108 -0
- package/lib/runtime/components/react/context.ts +18 -2
- package/lib/runtime/components/react/dist/KeyboardAvoidingView.jsx +89 -0
- package/lib/runtime/components/react/dist/context.js +1 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +1 -2
- package/lib/runtime/components/react/dist/mpx-button.jsx +1 -1
- 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 +50 -0
- package/lib/runtime/components/react/dist/mpx-image.jsx +19 -18
- package/lib/runtime/components/react/dist/mpx-input.jsx +48 -19
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +16 -14
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +2 -1
- package/lib/runtime/components/react/dist/mpx-portal/index.jsx +30 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +112 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +41 -0
- package/lib/runtime/components/react/dist/mpx-root-portal.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +19 -7
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-textarea.jsx +11 -3
- package/lib/runtime/components/react/dist/mpx-video.jsx +248 -0
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +149 -50
- package/lib/runtime/components/react/dist/useAnimationHooks.js +4 -4
- package/lib/runtime/components/react/dist/utils.jsx +8 -3
- package/lib/runtime/components/react/getInnerListeners.ts +1 -2
- package/lib/runtime/components/react/mpx-button.tsx +1 -1
- package/lib/runtime/components/react/mpx-icon/icons/cancel.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/clear.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/download.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/info.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/search.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/success.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/success_no_circle.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/waiting.png +0 -0
- package/lib/runtime/components/react/mpx-icon/icons/warn.png +0 -0
- package/lib/runtime/components/react/mpx-icon/index.tsx +111 -0
- package/lib/runtime/components/react/mpx-image.tsx +26 -14
- package/lib/runtime/components/react/mpx-input.tsx +52 -20
- package/lib/runtime/components/react/mpx-movable-view.tsx +19 -16
- package/lib/runtime/components/react/mpx-picker/time.tsx +2 -1
- package/lib/runtime/components/react/mpx-portal/index.tsx +39 -0
- package/lib/runtime/components/react/mpx-portal/portal-host.tsx +141 -0
- package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +64 -0
- package/lib/runtime/components/react/mpx-root-portal.tsx +1 -1
- package/lib/runtime/components/react/mpx-scroll-view.tsx +20 -8
- package/lib/runtime/components/react/mpx-swiper.tsx +3 -2
- package/lib/runtime/components/react/mpx-textarea.tsx +13 -3
- package/lib/runtime/components/react/mpx-video.tsx +388 -0
- package/lib/runtime/components/react/mpx-web-view.tsx +180 -49
- package/lib/runtime/components/react/types/getInnerListeners.d.ts +1 -1
- package/lib/runtime/components/react/types/global.d.ts +8 -0
- package/lib/runtime/components/react/useAnimationHooks.ts +4 -4
- package/lib/runtime/components/react/utils.tsx +12 -6
- package/lib/script-setup-compiler/index.js +6 -2
- package/lib/style-compiler/index.js +3 -4
- package/lib/style-compiler/strip-conditional-loader.js +127 -0
- package/lib/template-compiler/compiler.js +23 -9
- package/lib/template-compiler/index.js +4 -4
- package/lib/web/processTemplate.js +7 -5
- package/lib/wxs/loader.js +2 -2
- package/lib/wxs/pre-loader.js +2 -2
- package/package.json +7 -5
- package/lib/runtime/components/react/dist/mpx-icon.jsx +0 -41
- package/lib/runtime/components/react/mpx-icon.tsx +0 -102
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ✔ src
|
|
3
|
+
* ✘ duration
|
|
4
|
+
* ✔ controls
|
|
5
|
+
* ✘ danmu-list
|
|
6
|
+
* ✘ danmu-btn
|
|
7
|
+
* ✘ enable-danmu
|
|
8
|
+
* ✔ autoplay
|
|
9
|
+
* ✔ loop
|
|
10
|
+
* ✔ muted
|
|
11
|
+
* ✔ initial-time
|
|
12
|
+
* ✘ page-gesture
|
|
13
|
+
* ✘ direction
|
|
14
|
+
* ✘ show-progress
|
|
15
|
+
* ✘ show-fullscreen-btn
|
|
16
|
+
* ✘ show-play-btn
|
|
17
|
+
* ✘ show-center-play-btn
|
|
18
|
+
* ✘ enable-progress-gesture
|
|
19
|
+
* ✔ object-fit
|
|
20
|
+
* ✔ poster
|
|
21
|
+
* ✘ show-mute-btn
|
|
22
|
+
* ✘ title
|
|
23
|
+
* ✘ play-btn-position
|
|
24
|
+
* ✘ enable-play-gesture
|
|
25
|
+
* ✘ auto-pause-if-navigate
|
|
26
|
+
* ✘ auto-pause-if-open-native
|
|
27
|
+
* ✘ vslide-gesture
|
|
28
|
+
* ✘ vslide-gesture-in-fullscreen
|
|
29
|
+
* ✘ show-bottom-progress(use show-progress)
|
|
30
|
+
* ✘ ad-unit-id
|
|
31
|
+
* ✘ poster-for-crawler
|
|
32
|
+
* ✘ show-casting-button
|
|
33
|
+
* ✘ picture-in-picture-mode
|
|
34
|
+
* ✘ picture-in-picture-show-progress
|
|
35
|
+
* ✘ picture-in-picture-init-position
|
|
36
|
+
* ✔ enable-auto-rotation (only ios)
|
|
37
|
+
* ✘ show-screen-lock-button
|
|
38
|
+
* ✘ show-snapshot-button
|
|
39
|
+
* ✘ show-background-playback-button
|
|
40
|
+
* ✘ background-poster
|
|
41
|
+
* ✘ referrer-policy
|
|
42
|
+
* ✔ is-drm
|
|
43
|
+
* ✘ is-live
|
|
44
|
+
* ✔ provision-url(android)
|
|
45
|
+
* ✔ certificate-url(ios)
|
|
46
|
+
* ✔ license-url
|
|
47
|
+
* ✔ preferred-peak-bit-rate
|
|
48
|
+
* ✔ bindplay
|
|
49
|
+
* ✔ bindpause
|
|
50
|
+
* ✔ bindended
|
|
51
|
+
* ✘ bindtimeupdate
|
|
52
|
+
* ✔ bindfullscreenchange
|
|
53
|
+
* ✔ bindwaiting
|
|
54
|
+
* ✔ binderror
|
|
55
|
+
* ✘ bindprogress
|
|
56
|
+
* ✔ bindloadedmetadata
|
|
57
|
+
* ✔ bindcontrolstoggle(only android)
|
|
58
|
+
* ✘ bindenterpictureinpicture
|
|
59
|
+
* ✘ bindleavepictureinpicture
|
|
60
|
+
* ✔ bindseekcomplete
|
|
61
|
+
* ✘ bindcastinguserselect
|
|
62
|
+
* ✘ bindcastingstatechange
|
|
63
|
+
* ✘ bindcastinginterrupt
|
|
64
|
+
*/
|
|
65
|
+
import { useRef, forwardRef, createElement } from 'react';
|
|
66
|
+
import Video, { DRMType } from 'react-native-video';
|
|
67
|
+
import { StyleSheet, View, Platform } from 'react-native';
|
|
68
|
+
import { splitProps, useTransformStyle, useLayout, extendObject } from './utils';
|
|
69
|
+
import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
70
|
+
import useNodesRef from './useNodesRef';
|
|
71
|
+
const styles = StyleSheet.create({
|
|
72
|
+
container: {
|
|
73
|
+
width: 300,
|
|
74
|
+
height: 225
|
|
75
|
+
},
|
|
76
|
+
video: {
|
|
77
|
+
flex: 1
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
const MpxVideo = forwardRef((videoProps, ref) => {
|
|
81
|
+
const { innerProps: props = {} } = splitProps(videoProps);
|
|
82
|
+
const { src, autoplay = false, loop = false, muted = false, controls = true, poster = '', bindplay, bindpause, bindended, bindtimeupdate, bindfullscreenchange, bindwaiting, binderror, bindloadedmetadata, bindcontrolstoggle, bindseekcomplete, style, 'initial-time': initialTime = 0, 'object-fit': objectFit = 'contain', 'is-drm': isDrm = false, 'provision-url': provisionUrl, 'certificate-url': certificateUrl, 'license-url': licenseUrl, 'preferred-peak-bit-rate': preferredPeakBitRate = 0, 'enable-auto-rotation': enableAutoRotation = false, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
|
|
83
|
+
const videoRef = useRef(null);
|
|
84
|
+
const viewRef = useRef(null);
|
|
85
|
+
const videoInfoRef = useRef({});
|
|
86
|
+
const propsRef = useRef({});
|
|
87
|
+
propsRef.current = props;
|
|
88
|
+
const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(extendObject({}, styles.container, style), {
|
|
89
|
+
enableVar,
|
|
90
|
+
externalVarContext,
|
|
91
|
+
parentFontSize,
|
|
92
|
+
parentWidth,
|
|
93
|
+
parentHeight
|
|
94
|
+
});
|
|
95
|
+
const { layoutRef, layoutStyle, layoutProps } = useLayout({
|
|
96
|
+
props,
|
|
97
|
+
hasSelfPercent,
|
|
98
|
+
setWidth,
|
|
99
|
+
setHeight,
|
|
100
|
+
nodeRef: viewRef
|
|
101
|
+
});
|
|
102
|
+
useNodesRef(props, ref, viewRef, {
|
|
103
|
+
style: normalStyle,
|
|
104
|
+
node: {
|
|
105
|
+
play,
|
|
106
|
+
pause,
|
|
107
|
+
stop,
|
|
108
|
+
seek,
|
|
109
|
+
requestFullScreen,
|
|
110
|
+
exitFullScreen
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
function handleProgress(data) {
|
|
114
|
+
const { currentTime } = data;
|
|
115
|
+
bindtimeupdate && bindtimeupdate(getCustomEvent('timeupdate', {}, {
|
|
116
|
+
detail: {
|
|
117
|
+
currentTime,
|
|
118
|
+
duration: videoInfoRef.current.duration
|
|
119
|
+
},
|
|
120
|
+
layoutRef
|
|
121
|
+
}, propsRef.current));
|
|
122
|
+
}
|
|
123
|
+
function handleEnd() {
|
|
124
|
+
bindended(getCustomEvent('end', {}, { layoutRef }, propsRef.current));
|
|
125
|
+
}
|
|
126
|
+
function handleWaiting({ isBuffering }) {
|
|
127
|
+
if (isBuffering) {
|
|
128
|
+
bindwaiting(getCustomEvent('waiting', {}, { layoutRef }, propsRef.current));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function handleSeekcomplete({ seekTime }) {
|
|
132
|
+
// 手动拖拽进度条场景,android 可以触发,ios 不可以
|
|
133
|
+
bindseekcomplete(getCustomEvent('seekcomplete', {}, {
|
|
134
|
+
detail: {
|
|
135
|
+
position: Platform.OS === 'android' ? seekTime * 1000 : seekTime
|
|
136
|
+
},
|
|
137
|
+
layoutRef
|
|
138
|
+
}, propsRef.current));
|
|
139
|
+
}
|
|
140
|
+
function handleEnterFullScreen() {
|
|
141
|
+
bindfullscreenchange && bindfullscreenchange(getCustomEvent('fullscreenchange', {}, { detail: { fullScreen: 1 }, layoutRef }, propsRef.current));
|
|
142
|
+
}
|
|
143
|
+
function handleExitFullScreen() {
|
|
144
|
+
bindfullscreenchange && bindfullscreenchange(getCustomEvent('fullscreenchange', {}, { detail: { fullScreen: 0 }, layoutRef }, propsRef.current));
|
|
145
|
+
}
|
|
146
|
+
function handlePlaybackRateChange({ playbackRate }) {
|
|
147
|
+
if (playbackRate === 0) {
|
|
148
|
+
bindpause && bindpause(getCustomEvent('pause', {}, { layoutRef }, propsRef.current));
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
bindplay && bindplay(getCustomEvent('play', {}, { layoutRef }, propsRef.current));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function handleAndroidControlsVisibilityChange({ isVisible }) {
|
|
155
|
+
bindcontrolstoggle(getCustomEvent('progress', {}, {
|
|
156
|
+
detail: {
|
|
157
|
+
show: isVisible
|
|
158
|
+
},
|
|
159
|
+
layoutRef
|
|
160
|
+
}, propsRef.current));
|
|
161
|
+
}
|
|
162
|
+
function handleVideoLoad(data) {
|
|
163
|
+
const { naturalSize, duration } = data;
|
|
164
|
+
if (initialTime) {
|
|
165
|
+
videoRef.current && videoRef.current.seek(initialTime);
|
|
166
|
+
}
|
|
167
|
+
videoInfoRef.current = data;
|
|
168
|
+
bindloadedmetadata && bindloadedmetadata(getCustomEvent('loadedmetadata', {}, {
|
|
169
|
+
detail: {
|
|
170
|
+
width: naturalSize.width,
|
|
171
|
+
height: naturalSize.height,
|
|
172
|
+
duration
|
|
173
|
+
},
|
|
174
|
+
layoutRef
|
|
175
|
+
}, propsRef.current));
|
|
176
|
+
}
|
|
177
|
+
function handleError({ error }) {
|
|
178
|
+
binderror && binderror(getCustomEvent('play', {}, { detail: { errMsg: error.localizedFailureReason }, layoutRef }, propsRef.current));
|
|
179
|
+
}
|
|
180
|
+
function play() {
|
|
181
|
+
videoRef.current && videoRef.current.resume();
|
|
182
|
+
}
|
|
183
|
+
function pause() {
|
|
184
|
+
videoRef.current && videoRef.current.pause();
|
|
185
|
+
}
|
|
186
|
+
function seek(position) {
|
|
187
|
+
videoRef.current && videoRef.current.seek(position);
|
|
188
|
+
}
|
|
189
|
+
function stop() {
|
|
190
|
+
videoRef.current && videoRef.current.pause();
|
|
191
|
+
seek(0);
|
|
192
|
+
}
|
|
193
|
+
function exitFullScreen() {
|
|
194
|
+
videoRef.current && videoRef.current.setFullScreen(false);
|
|
195
|
+
}
|
|
196
|
+
function requestFullScreen() {
|
|
197
|
+
videoRef.current && videoRef.current.setFullScreen(true);
|
|
198
|
+
}
|
|
199
|
+
const source = {
|
|
200
|
+
uri: src
|
|
201
|
+
};
|
|
202
|
+
if (isDrm) {
|
|
203
|
+
source.drm = {
|
|
204
|
+
type: DRMType.FAIRPLAY,
|
|
205
|
+
certificateUrl: Platform.OS === 'android' ? provisionUrl : certificateUrl,
|
|
206
|
+
licenseServer: licenseUrl
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const innerProps = useInnerProps(props, extendObject({
|
|
210
|
+
style: styles.video,
|
|
211
|
+
ref: videoRef,
|
|
212
|
+
source,
|
|
213
|
+
paused: !autoplay,
|
|
214
|
+
repeat: loop,
|
|
215
|
+
muted,
|
|
216
|
+
controls,
|
|
217
|
+
maxBitRate: preferredPeakBitRate,
|
|
218
|
+
fullscreenAutorotate: enableAutoRotation,
|
|
219
|
+
resizeMode: objectFit === 'fill' ? 'stretch' : objectFit,
|
|
220
|
+
poster: controls ? poster : '',
|
|
221
|
+
onProgress: bindtimeupdate && handleProgress,
|
|
222
|
+
onEnd: bindended && handleEnd,
|
|
223
|
+
onError: binderror && handleError,
|
|
224
|
+
onBuffer: bindwaiting && handleWaiting,
|
|
225
|
+
onSeek: bindseekcomplete && handleSeekcomplete,
|
|
226
|
+
onPlaybackRateChange: (bindpause || bindplay) && handlePlaybackRateChange,
|
|
227
|
+
onFullscreenPlayerDidPresent: bindfullscreenchange && handleEnterFullScreen,
|
|
228
|
+
onFullscreenPlayerWillDismiss: bindfullscreenchange && handleExitFullScreen,
|
|
229
|
+
onControlsVisibilityChange: bindcontrolstoggle && handleAndroidControlsVisibilityChange,
|
|
230
|
+
onLoad: handleVideoLoad
|
|
231
|
+
}, layoutProps), [
|
|
232
|
+
'src',
|
|
233
|
+
'autoplay',
|
|
234
|
+
'loop',
|
|
235
|
+
'bindplay',
|
|
236
|
+
'bindpause',
|
|
237
|
+
'bindended',
|
|
238
|
+
'bindtimeupdate',
|
|
239
|
+
'bindfullscreenchange',
|
|
240
|
+
'bindwaiting',
|
|
241
|
+
'binderror',
|
|
242
|
+
'bindloadedmetadata',
|
|
243
|
+
'bindcontrolstoggle',
|
|
244
|
+
'bindseekcomplete'
|
|
245
|
+
], { layoutRef });
|
|
246
|
+
return createElement(View, { style: extendObject({}, normalStyle, layoutStyle), ref: viewRef }, createElement(Video, innerProps));
|
|
247
|
+
});
|
|
248
|
+
export default MpxVideo;
|
|
@@ -1,21 +1,62 @@
|
|
|
1
|
-
import { forwardRef, useRef, useContext, useMemo,
|
|
2
|
-
import { warn,
|
|
3
|
-
import
|
|
1
|
+
import { forwardRef, useRef, useContext, useMemo, useState, useEffect } from 'react';
|
|
2
|
+
import { warn, isFunction } from '@mpxjs/utils';
|
|
3
|
+
import Portal from './mpx-portal/index';
|
|
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, useNavigation } from './utils';
|
|
9
9
|
import { RouteContext } from './context';
|
|
10
|
+
import { StyleSheet, View, Text } from 'react-native';
|
|
11
|
+
const styles = StyleSheet.create({
|
|
12
|
+
loadErrorContext: {
|
|
13
|
+
display: 'flex',
|
|
14
|
+
alignItems: 'center'
|
|
15
|
+
},
|
|
16
|
+
loadErrorText: {
|
|
17
|
+
fontSize: 12,
|
|
18
|
+
color: '#666666',
|
|
19
|
+
paddingTop: '40%',
|
|
20
|
+
paddingBottom: 20,
|
|
21
|
+
paddingLeft: '10%',
|
|
22
|
+
paddingRight: '10%',
|
|
23
|
+
textAlign: 'center'
|
|
24
|
+
},
|
|
25
|
+
loadErrorButton: {
|
|
26
|
+
color: '#666666',
|
|
27
|
+
textAlign: 'center',
|
|
28
|
+
padding: 10,
|
|
29
|
+
borderColor: '#666666',
|
|
30
|
+
borderStyle: 'solid',
|
|
31
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
32
|
+
borderRadius: 10
|
|
33
|
+
}
|
|
34
|
+
});
|
|
10
35
|
const _WebView = forwardRef((props, ref) => {
|
|
11
36
|
const { src, bindmessage, bindload, binderror } = props;
|
|
12
37
|
const mpx = global.__mpx;
|
|
38
|
+
const errorText = {
|
|
39
|
+
'zh-CN': {
|
|
40
|
+
text: '网络不可用,请检查网络设置',
|
|
41
|
+
button: '重新加载'
|
|
42
|
+
},
|
|
43
|
+
'en-US': {
|
|
44
|
+
text: 'The network is not available. Please check the network settings',
|
|
45
|
+
button: 'Reload'
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const currentErrorText = errorText[mpx.i18n.locale || 'zh-CN'];
|
|
13
49
|
if (props.style) {
|
|
14
50
|
warn('The web-view component does not support the style prop.');
|
|
15
51
|
}
|
|
16
|
-
const pageId = useContext(RouteContext);
|
|
52
|
+
const { pageId } = useContext(RouteContext) || {};
|
|
53
|
+
const [pageLoadErr, setPageLoadErr] = useState(false);
|
|
17
54
|
const currentPage = useMemo(() => getCurrentPage(pageId), [pageId]);
|
|
18
55
|
const webViewRef = useRef(null);
|
|
56
|
+
const fristLoaded = useRef(false);
|
|
57
|
+
const isLoadError = useRef(false);
|
|
58
|
+
const statusCode = useRef('');
|
|
59
|
+
const [isLoaded, setIsLoaded] = useState(true);
|
|
19
60
|
const defaultWebViewStyle = {
|
|
20
61
|
position: 'absolute',
|
|
21
62
|
left: 0,
|
|
@@ -23,31 +64,35 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
23
64
|
top: 0,
|
|
24
65
|
bottom: 0
|
|
25
66
|
};
|
|
67
|
+
const canGoBack = useRef(false);
|
|
68
|
+
const isNavigateBack = useRef(false);
|
|
69
|
+
const beforeRemoveHandle = (e) => {
|
|
70
|
+
if (canGoBack.current && !isNavigateBack.current) {
|
|
71
|
+
webViewRef.current?.goBack();
|
|
72
|
+
e.preventDefault();
|
|
73
|
+
}
|
|
74
|
+
isNavigateBack.current = false;
|
|
75
|
+
};
|
|
76
|
+
const navigation = useNavigation();
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
const beforeRemoveSubscription = navigation?.addListener?.('beforeRemove', beforeRemoveHandle);
|
|
79
|
+
return () => {
|
|
80
|
+
if (isFunction(beforeRemoveSubscription)) {
|
|
81
|
+
beforeRemoveSubscription();
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}, []);
|
|
26
85
|
useNodesRef(props, ref, webViewRef, {
|
|
27
86
|
style: defaultWebViewStyle
|
|
28
87
|
});
|
|
29
88
|
if (!src) {
|
|
30
89
|
return null;
|
|
31
90
|
}
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
src: res.nativeEvent?.url
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
bindload(result);
|
|
41
|
-
};
|
|
42
|
-
const _error = function (res) {
|
|
43
|
-
const result = {
|
|
44
|
-
type: 'error',
|
|
45
|
-
timeStamp: res.timeStamp,
|
|
46
|
-
detail: {
|
|
47
|
-
src: ''
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
binderror(result);
|
|
91
|
+
const _reload = function () {
|
|
92
|
+
if (__mpx_mode__ === 'android') {
|
|
93
|
+
fristLoaded.current = false; // 安卓需要重新设置
|
|
94
|
+
}
|
|
95
|
+
setPageLoadErr(false);
|
|
51
96
|
};
|
|
52
97
|
const injectedJavaScript = `
|
|
53
98
|
if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
|
|
@@ -73,12 +118,25 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
73
118
|
}
|
|
74
119
|
});
|
|
75
120
|
}
|
|
121
|
+
true;
|
|
76
122
|
`;
|
|
123
|
+
const sendMessage = function (params) {
|
|
124
|
+
return `
|
|
125
|
+
window.mpxWebviewMessageCallback && window.mpxWebviewMessageCallback(${params})
|
|
126
|
+
true;
|
|
127
|
+
`;
|
|
128
|
+
};
|
|
77
129
|
const _changeUrl = function (navState) {
|
|
78
130
|
if (navState.navigationType) { // navigationType这个事件在页面开始加载时和页面加载完成时都会被触发所以判断这个避免其他无效触发执行该逻辑
|
|
131
|
+
canGoBack.current = navState.canGoBack;
|
|
79
132
|
currentPage.__webViewUrl = navState.url;
|
|
80
133
|
}
|
|
81
134
|
};
|
|
135
|
+
const _onLoadProgress = function (event) {
|
|
136
|
+
if (__mpx_mode__ === 'android') {
|
|
137
|
+
canGoBack.current = event.nativeEvent.canGoBack;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
82
140
|
const _message = function (res) {
|
|
83
141
|
let data = {};
|
|
84
142
|
let asyncCallback;
|
|
@@ -99,7 +157,6 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
99
157
|
{ // case下不允许直接声明,包个块解决该问题
|
|
100
158
|
const title = postData._documentTitle;
|
|
101
159
|
if (title) {
|
|
102
|
-
const navigation = getFocusedNavigation();
|
|
103
160
|
navigation && navigation.setOptions({ title });
|
|
104
161
|
}
|
|
105
162
|
}
|
|
@@ -118,6 +175,7 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
118
175
|
asyncCallback = navObj.navigateTo(...params);
|
|
119
176
|
break;
|
|
120
177
|
case 'navigateBack':
|
|
178
|
+
isNavigateBack.current = true;
|
|
121
179
|
asyncCallback = navObj.navigateBack(...params);
|
|
122
180
|
break;
|
|
123
181
|
case 'redirectTo':
|
|
@@ -146,45 +204,86 @@ const _WebView = forwardRef((props, ref) => {
|
|
|
146
204
|
}
|
|
147
205
|
asyncCallback && asyncCallback.then((res) => {
|
|
148
206
|
if (webViewRef.current?.postMessage) {
|
|
149
|
-
const
|
|
207
|
+
const result = JSON.stringify({
|
|
150
208
|
type,
|
|
151
209
|
callbackId: data.callbackId,
|
|
152
210
|
result: res
|
|
153
211
|
});
|
|
154
|
-
webViewRef.current.
|
|
212
|
+
webViewRef.current.injectJavaScript(sendMessage(result));
|
|
155
213
|
}
|
|
156
214
|
}).catch((error) => {
|
|
157
215
|
if (webViewRef.current?.postMessage) {
|
|
158
|
-
const
|
|
216
|
+
const result = JSON.stringify({
|
|
159
217
|
type,
|
|
160
218
|
callbackId: data.callbackId,
|
|
161
219
|
error
|
|
162
220
|
});
|
|
163
|
-
webViewRef.current.
|
|
221
|
+
webViewRef.current.injectJavaScript(sendMessage(result));
|
|
164
222
|
}
|
|
165
223
|
});
|
|
166
224
|
};
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
225
|
+
const onLoadEndHandle = function (res) {
|
|
226
|
+
fristLoaded.current = true;
|
|
227
|
+
setIsLoaded(true);
|
|
228
|
+
const src = res.nativeEvent?.url;
|
|
229
|
+
if (isLoadError.current) {
|
|
230
|
+
isLoadError.current = false;
|
|
231
|
+
isNavigateBack.current = false;
|
|
232
|
+
const result = {
|
|
233
|
+
type: 'error',
|
|
234
|
+
timeStamp: res.timeStamp,
|
|
235
|
+
detail: {
|
|
236
|
+
src,
|
|
237
|
+
statusCode: statusCode.current
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
binderror && binderror(result);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
const result = {
|
|
244
|
+
type: 'load',
|
|
245
|
+
timeStamp: res.timeStamp,
|
|
246
|
+
detail: {
|
|
247
|
+
src
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
bindload?.(result);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
const onLoadEnd = function (res) {
|
|
254
|
+
if (__mpx_mode__ === 'android') {
|
|
255
|
+
setTimeout(() => {
|
|
256
|
+
onLoadEndHandle(res);
|
|
257
|
+
}, 0);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
onLoadEndHandle(res);
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
const onHttpError = function (res) {
|
|
264
|
+
isLoadError.current = true;
|
|
265
|
+
statusCode.current = res.nativeEvent?.statusCode;
|
|
266
|
+
};
|
|
267
|
+
const onError = function () {
|
|
268
|
+
statusCode.current = '';
|
|
269
|
+
isLoadError.current = true;
|
|
270
|
+
if (!fristLoaded.current) {
|
|
271
|
+
setPageLoadErr(true);
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
const onLoadStart = function () {
|
|
275
|
+
if (!fristLoaded.current) {
|
|
276
|
+
setIsLoaded(false);
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
return (<Portal key={pageLoadErr ? 'error' : 'webview'}>
|
|
280
|
+
{pageLoadErr
|
|
281
|
+
? (<View style={[styles.loadErrorContext, defaultWebViewStyle]}>
|
|
282
|
+
<View style={styles.loadErrorText}><Text style={{ fontSize: 14, color: '#999999' }}>{currentErrorText.text}</Text></View>
|
|
283
|
+
<View style={styles.loadErrorButton} onTouchEnd={_reload}><Text style={{ fontSize: 12, color: '#666666' }}>{currentErrorText.button}</Text></View>
|
|
284
|
+
</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={isLoaded}></WebView>)}
|
|
286
|
+
</Portal>);
|
|
188
287
|
});
|
|
189
288
|
_WebView.displayName = 'MpxWebview';
|
|
190
289
|
export default _WebView;
|
|
@@ -4,10 +4,10 @@ import { error } from '@mpxjs/utils';
|
|
|
4
4
|
// 微信 timingFunction 和 RN Easing 对应关系
|
|
5
5
|
const EasingKey = {
|
|
6
6
|
linear: Easing.linear,
|
|
7
|
-
ease: Easing.ease,
|
|
8
|
-
'ease-in': Easing.in(Easing.
|
|
9
|
-
'ease-in-out': Easing.inOut(Easing.
|
|
10
|
-
'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))
|
|
11
11
|
// 'step-start': '',
|
|
12
12
|
// 'step-end': ''
|
|
13
13
|
};
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { useEffect, useCallback, useMemo, useRef, isValidElement, useContext, useState, Children, cloneElement } from 'react';
|
|
2
2
|
import { Image } from 'react-native';
|
|
3
3
|
import { isObject, isFunction, isNumber, hasOwn, diffAndCloneA, error, warn } from '@mpxjs/utils';
|
|
4
|
-
import { VarContext, ScrollViewContext } from './context';
|
|
4
|
+
import { VarContext, ScrollViewContext, RouteContext } from './context';
|
|
5
5
|
import { ExpressionParser, parseFunc, ReplaceSource } from './parser';
|
|
6
6
|
import { initialWindowMetrics } from 'react-native-safe-area-context';
|
|
7
|
-
import { useNavigation } from '@react-navigation/native';
|
|
8
7
|
import FastImage from '@d11/react-native-fast-image';
|
|
9
8
|
import { runOnJS } from 'react-native-reanimated';
|
|
10
9
|
import { Gesture } from 'react-native-gesture-handler';
|
|
@@ -36,6 +35,10 @@ function getSafeAreaInset(name, navigation) {
|
|
|
36
35
|
const insets = extendObject({}, initialWindowMetrics?.insets, navigation?.insets);
|
|
37
36
|
return insets[safeAreaInsetMap[name]];
|
|
38
37
|
}
|
|
38
|
+
export function useNavigation() {
|
|
39
|
+
const { navigation } = useContext(RouteContext) || {};
|
|
40
|
+
return navigation;
|
|
41
|
+
}
|
|
39
42
|
export function omit(obj, fields) {
|
|
40
43
|
const shallowCopy = extendObject({}, obj);
|
|
41
44
|
for (let i = 0; i < fields.length; i += 1) {
|
|
@@ -438,6 +441,7 @@ export const useLayout = ({ props, hasSelfPercent, setWidth, setHeight, onLayout
|
|
|
438
441
|
const hasLayoutRef = useRef(false);
|
|
439
442
|
const layoutStyle = useMemo(() => { return !hasLayoutRef.current && hasSelfPercent ? HIDDEN_STYLE : {}; }, [hasLayoutRef.current]);
|
|
440
443
|
const layoutProps = {};
|
|
444
|
+
const navigation = useNavigation();
|
|
441
445
|
const enableOffset = props['enable-offset'];
|
|
442
446
|
if (hasSelfPercent || onLayout || enableOffset) {
|
|
443
447
|
layoutProps.onLayout = (e) => {
|
|
@@ -449,7 +453,8 @@ export const useLayout = ({ props, hasSelfPercent, setWidth, setHeight, onLayout
|
|
|
449
453
|
}
|
|
450
454
|
if (enableOffset) {
|
|
451
455
|
nodeRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
|
|
452
|
-
|
|
456
|
+
const { y: navigationY = 0 } = navigation?.layout || {};
|
|
457
|
+
layoutRef.current = { x, y: y - navigationY, width, height, offsetLeft, offsetTop: offsetTop - navigationY };
|
|
453
458
|
});
|
|
454
459
|
}
|
|
455
460
|
onLayout && onLayout(e);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useRef, useMemo, RefObject } from 'react'
|
|
2
2
|
import { hasOwn, collectDataset } from '@mpxjs/utils'
|
|
3
|
-
import { useNavigation } from '
|
|
4
|
-
import { omit, extendObject } from './utils'
|
|
3
|
+
import { omit, extendObject, useNavigation } from './utils'
|
|
5
4
|
import eventConfigMap from './event.config'
|
|
6
5
|
import {
|
|
7
6
|
Props,
|
|
@@ -219,7 +219,7 @@ const Button = forwardRef<HandlerRef<View, ButtonProps>, ButtonProps>((buttonPro
|
|
|
219
219
|
bindtap
|
|
220
220
|
} = props
|
|
221
221
|
|
|
222
|
-
const pageId = useContext(RouteContext)
|
|
222
|
+
const { pageId } = useContext(RouteContext) || {}
|
|
223
223
|
|
|
224
224
|
const formContext = useContext(FormContext)
|
|
225
225
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|