@mpxjs/webpack-plugin 2.9.73 → 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.
Files changed (80) hide show
  1. package/lib/file-loader.js +5 -0
  2. package/lib/index.js +21 -3
  3. package/lib/platform/template/wx/component-config/input.js +1 -1
  4. package/lib/platform/template/wx/component-config/textarea.js +1 -1
  5. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  6. package/lib/platform/template/wx/component-config/video.js +28 -1
  7. package/lib/platform/template/wx/index.js +2 -2
  8. package/lib/react/processScript.js +6 -4
  9. package/lib/react/processTemplate.js +5 -3
  10. package/lib/runtime/components/react/KeyboardAvoidingView.tsx +108 -0
  11. package/lib/runtime/components/react/context.ts +18 -2
  12. package/lib/runtime/components/react/dist/KeyboardAvoidingView.jsx +89 -0
  13. package/lib/runtime/components/react/dist/context.js +1 -0
  14. package/lib/runtime/components/react/dist/getInnerListeners.js +1 -2
  15. package/lib/runtime/components/react/dist/mpx-button.jsx +1 -1
  16. package/lib/runtime/components/react/dist/mpx-icon/icons/cancel.png +0 -0
  17. package/lib/runtime/components/react/dist/mpx-icon/icons/clear.png +0 -0
  18. package/lib/runtime/components/react/dist/mpx-icon/icons/download.png +0 -0
  19. package/lib/runtime/components/react/dist/mpx-icon/icons/info.png +0 -0
  20. package/lib/runtime/components/react/dist/mpx-icon/icons/search.png +0 -0
  21. package/lib/runtime/components/react/dist/mpx-icon/icons/success.png +0 -0
  22. package/lib/runtime/components/react/dist/mpx-icon/icons/success_no_circle.png +0 -0
  23. package/lib/runtime/components/react/dist/mpx-icon/icons/waiting.png +0 -0
  24. package/lib/runtime/components/react/dist/mpx-icon/icons/warn.png +0 -0
  25. package/lib/runtime/components/react/dist/mpx-icon/index.jsx +50 -0
  26. package/lib/runtime/components/react/dist/mpx-image.jsx +19 -18
  27. package/lib/runtime/components/react/dist/mpx-input.jsx +48 -19
  28. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +16 -14
  29. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +2 -1
  30. package/lib/runtime/components/react/dist/mpx-portal/index.jsx +30 -0
  31. package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +112 -0
  32. package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +41 -0
  33. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +1 -1
  34. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +19 -7
  35. package/lib/runtime/components/react/dist/mpx-swiper.jsx +3 -2
  36. package/lib/runtime/components/react/dist/mpx-textarea.jsx +11 -3
  37. package/lib/runtime/components/react/dist/mpx-video.jsx +248 -0
  38. package/lib/runtime/components/react/dist/mpx-web-view.jsx +149 -50
  39. package/lib/runtime/components/react/dist/useAnimationHooks.js +4 -4
  40. package/lib/runtime/components/react/dist/utils.jsx +8 -3
  41. package/lib/runtime/components/react/getInnerListeners.ts +1 -2
  42. package/lib/runtime/components/react/mpx-button.tsx +1 -1
  43. package/lib/runtime/components/react/mpx-icon/icons/cancel.png +0 -0
  44. package/lib/runtime/components/react/mpx-icon/icons/clear.png +0 -0
  45. package/lib/runtime/components/react/mpx-icon/icons/download.png +0 -0
  46. package/lib/runtime/components/react/mpx-icon/icons/info.png +0 -0
  47. package/lib/runtime/components/react/mpx-icon/icons/search.png +0 -0
  48. package/lib/runtime/components/react/mpx-icon/icons/success.png +0 -0
  49. package/lib/runtime/components/react/mpx-icon/icons/success_no_circle.png +0 -0
  50. package/lib/runtime/components/react/mpx-icon/icons/waiting.png +0 -0
  51. package/lib/runtime/components/react/mpx-icon/icons/warn.png +0 -0
  52. package/lib/runtime/components/react/mpx-icon/index.tsx +111 -0
  53. package/lib/runtime/components/react/mpx-image.tsx +26 -14
  54. package/lib/runtime/components/react/mpx-input.tsx +52 -20
  55. package/lib/runtime/components/react/mpx-movable-view.tsx +19 -16
  56. package/lib/runtime/components/react/mpx-picker/time.tsx +2 -1
  57. package/lib/runtime/components/react/mpx-portal/index.tsx +39 -0
  58. package/lib/runtime/components/react/mpx-portal/portal-host.tsx +141 -0
  59. package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +64 -0
  60. package/lib/runtime/components/react/mpx-root-portal.tsx +1 -1
  61. package/lib/runtime/components/react/mpx-scroll-view.tsx +20 -8
  62. package/lib/runtime/components/react/mpx-swiper.tsx +3 -2
  63. package/lib/runtime/components/react/mpx-textarea.tsx +13 -3
  64. package/lib/runtime/components/react/mpx-video.tsx +388 -0
  65. package/lib/runtime/components/react/mpx-web-view.tsx +180 -49
  66. package/lib/runtime/components/react/types/getInnerListeners.d.ts +1 -1
  67. package/lib/runtime/components/react/types/global.d.ts +8 -0
  68. package/lib/runtime/components/react/useAnimationHooks.ts +4 -4
  69. package/lib/runtime/components/react/utils.tsx +12 -6
  70. package/lib/script-setup-compiler/index.js +6 -2
  71. package/lib/style-compiler/index.js +3 -4
  72. package/lib/style-compiler/strip-conditional-loader.js +127 -0
  73. package/lib/template-compiler/compiler.js +15 -8
  74. package/lib/template-compiler/index.js +4 -4
  75. package/lib/web/processTemplate.js +7 -5
  76. package/lib/wxs/loader.js +2 -2
  77. package/lib/wxs/pre-loader.js +2 -2
  78. package/package.json +7 -5
  79. package/lib/runtime/components/react/dist/mpx-icon.jsx +0 -41
  80. 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, createElement } from 'react';
2
- import { warn, getFocusedNavigation, isFunction } from '@mpxjs/utils';
3
- import { Portal } from '@ant-design/react-native';
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, extendObject } from './utils';
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 _load = function (res) {
33
- const result = {
34
- type: 'load',
35
- timeStamp: res.timeStamp,
36
- detail: {
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 test = JSON.stringify({
207
+ const result = JSON.stringify({
150
208
  type,
151
209
  callbackId: data.callbackId,
152
210
  result: res
153
211
  });
154
- webViewRef.current.postMessage(test);
212
+ webViewRef.current.injectJavaScript(sendMessage(result));
155
213
  }
156
214
  }).catch((error) => {
157
215
  if (webViewRef.current?.postMessage) {
158
- const test = JSON.stringify({
216
+ const result = JSON.stringify({
159
217
  type,
160
218
  callbackId: data.callbackId,
161
219
  error
162
220
  });
163
- webViewRef.current.postMessage(test);
221
+ webViewRef.current.injectJavaScript(sendMessage(result));
164
222
  }
165
223
  });
166
224
  };
167
- const events = {};
168
- if (bindload) {
169
- extendObject(events, {
170
- onLoad: _load
171
- });
172
- }
173
- if (binderror) {
174
- extendObject(events, {
175
- onError: _error
176
- });
177
- }
178
- extendObject(events, {
179
- onMessage: _message
180
- });
181
- return createElement(Portal, null, createElement(WebView, extendObject({
182
- style: defaultWebViewStyle,
183
- source: { uri: src },
184
- ref: webViewRef,
185
- javaScriptEnabled: true,
186
- onNavigationStateChange: _changeUrl
187
- }, events)));
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.ease),
9
- 'ease-in-out': Easing.inOut(Easing.ease),
10
- 'ease-out': Easing.out(Easing.ease)
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
- layoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
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 '@react-navigation/native'
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