@mpxjs/core 2.10.4-beta.2 → 2.10.4-beta.20
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/package.json +2 -2
- package/src/platform/builtInMixins/styleHelperMixin.ios.js +3 -1
- package/src/platform/createApp.ios.js +83 -77
- package/src/platform/env/nav.js +130 -0
- package/src/platform/env/navigationHelper.android.js +2 -2
- package/src/platform/env/navigationHelper.ios.js +2 -2
- package/src/platform/patch/getDefaultOptions.ios.js +52 -76
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpxjs/core",
|
|
3
|
-
"version": "2.10.4-beta.
|
|
3
|
+
"version": "2.10.4-beta.20",
|
|
4
4
|
"description": "mpx runtime core",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"miniprogram",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"@d11/react-native-fast-image": "*",
|
|
28
|
-
"@mpxjs/api-proxy": "^2.
|
|
28
|
+
"@mpxjs/api-proxy": "^2.10.4-beta.0",
|
|
29
29
|
"@mpxjs/store": "^2.9.0",
|
|
30
30
|
"@react-navigation/native": "*",
|
|
31
31
|
"@react-navigation/native-stack": "*",
|
|
@@ -2,12 +2,14 @@ import { isObject, isArray, dash2hump, cached, isEmptyObject } from '@mpxjs/util
|
|
|
2
2
|
import { Dimensions, StyleSheet } from 'react-native'
|
|
3
3
|
|
|
4
4
|
let { width, height } = Dimensions.get('screen')
|
|
5
|
+
// TODO 临时适配折叠屏场景适配
|
|
6
|
+
const isLargeFoldableLike = (__mpx_mode__ === 'android') && (height / width < 1.5) && (width > 600)
|
|
7
|
+
if (isLargeFoldableLike) width = width / 2
|
|
5
8
|
|
|
6
9
|
Dimensions.addEventListener('change', ({ screen }) => {
|
|
7
10
|
width = screen.width
|
|
8
11
|
height = screen.height
|
|
9
12
|
})
|
|
10
|
-
|
|
11
13
|
function rpx (value) {
|
|
12
14
|
// rn 单位 dp = 1(css)px = 1 物理像素 * pixelRatio(像素比)
|
|
13
15
|
// px = rpx * (750 / 屏幕宽度)
|
|
@@ -4,10 +4,12 @@ import { makeMap, spreadProp, getFocusedNavigation, hasOwn } from '@mpxjs/utils'
|
|
|
4
4
|
import { mergeLifecycle } from '../convertor/mergeLifecycle'
|
|
5
5
|
import { LIFECYCLE } from '../platform/patch/lifecycle/index'
|
|
6
6
|
import Mpx from '../index'
|
|
7
|
+
import { reactive } from '../observer/reactive'
|
|
8
|
+
import { watch } from '../observer/watch'
|
|
7
9
|
import { createElement, memo, useRef, useEffect } from 'react'
|
|
8
10
|
import * as ReactNative from 'react-native'
|
|
9
11
|
import { initAppProvides } from './export/inject'
|
|
10
|
-
import { NavigationContainer,
|
|
12
|
+
import { NavigationContainer, createNativeStackNavigator, SafeAreaProvider } from './env/navigationHelper'
|
|
11
13
|
|
|
12
14
|
const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
|
|
13
15
|
|
|
@@ -52,25 +54,25 @@ export default function createApp (options) {
|
|
|
52
54
|
|
|
53
55
|
const pages = currentInject.getPages() || {}
|
|
54
56
|
const firstPage = currentInject.firstPage
|
|
55
|
-
const Stack =
|
|
57
|
+
const Stack = createNativeStackNavigator()
|
|
56
58
|
const getPageScreens = (initialRouteName, initialParams) => {
|
|
57
59
|
return Object.entries(pages).map(([key, item]) => {
|
|
58
|
-
const options = {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
60
|
+
// const options = {
|
|
61
|
+
// // __mpxPageStatusMap 为编译注入的全局变量
|
|
62
|
+
// headerShown: !(Object.assign({}, global.__mpxPageConfig, global.__mpxPageConfigsMap[key]).navigationStyle === 'custom')
|
|
63
|
+
// }
|
|
62
64
|
if (key === initialRouteName) {
|
|
63
65
|
return createElement(Stack.Screen, {
|
|
64
66
|
name: key,
|
|
65
67
|
component: item,
|
|
66
|
-
initialParams
|
|
67
|
-
options
|
|
68
|
+
initialParams
|
|
69
|
+
// options
|
|
68
70
|
})
|
|
69
71
|
}
|
|
70
72
|
return createElement(Stack.Screen, {
|
|
71
73
|
name: key,
|
|
72
|
-
component: item
|
|
73
|
-
options
|
|
74
|
+
component: item
|
|
75
|
+
// options
|
|
74
76
|
})
|
|
75
77
|
})
|
|
76
78
|
}
|
|
@@ -90,6 +92,57 @@ export default function createApp (options) {
|
|
|
90
92
|
global.__navigationHelper.lastFailCallback = null
|
|
91
93
|
}
|
|
92
94
|
}
|
|
95
|
+
const appState = reactive({ state: '' })
|
|
96
|
+
// TODO hideReason 暂未完全模拟
|
|
97
|
+
// 0用户退出小程序
|
|
98
|
+
// 1进入其他小程序
|
|
99
|
+
// 2打开原生功能页
|
|
100
|
+
// 3其他
|
|
101
|
+
watch(() => appState.state, (value) => {
|
|
102
|
+
if (value === 'show') {
|
|
103
|
+
let options = appState.showOptions
|
|
104
|
+
delete appState.showOptions
|
|
105
|
+
if (!options) {
|
|
106
|
+
const navigation = getFocusedNavigation()
|
|
107
|
+
if (navigation) {
|
|
108
|
+
const state = navigation.getState()
|
|
109
|
+
const current = state.routes[state.index]
|
|
110
|
+
options = {
|
|
111
|
+
path: current.name,
|
|
112
|
+
query: current.params,
|
|
113
|
+
scene: 0,
|
|
114
|
+
shareTicket: '',
|
|
115
|
+
referrerInfo: {}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
global.__mpxAppCbs.show.forEach((cb) => {
|
|
120
|
+
cb(options || {})
|
|
121
|
+
})
|
|
122
|
+
} else if (value === 'hide') {
|
|
123
|
+
global.__mpxAppCbs.hide.forEach((cb) => {
|
|
124
|
+
cb({
|
|
125
|
+
reason: appState.hideReason ?? 3
|
|
126
|
+
})
|
|
127
|
+
delete appState.hideReason
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
}, { sync: true })
|
|
131
|
+
const onAppStateChange = (currentState) => {
|
|
132
|
+
const navigation = getFocusedNavigation()
|
|
133
|
+
if (currentState === 'active') {
|
|
134
|
+
appState.state = 'show'
|
|
135
|
+
if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
|
|
136
|
+
global.__mpxPageStatusMap[navigation.pageId] = 'show'
|
|
137
|
+
}
|
|
138
|
+
} else if (currentState === 'inactive' || currentState === 'background') {
|
|
139
|
+
appState.hideReason = 3
|
|
140
|
+
appState.state = 'hide'
|
|
141
|
+
if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
|
|
142
|
+
global.__mpxPageStatusMap[navigation.pageId] = 'hide'
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
93
146
|
|
|
94
147
|
global.__mpxAppLaunched = false
|
|
95
148
|
global.__mpxOptionsMap[currentInject.moduleId] = memo((props) => {
|
|
@@ -127,47 +180,18 @@ export default function createApp (options) {
|
|
|
127
180
|
global.__mpxLaunchOptions = options
|
|
128
181
|
defaultOptions.onLaunch && defaultOptions.onLaunch.call(appInstance, options)
|
|
129
182
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
})
|
|
183
|
+
appState.showOptions = options
|
|
184
|
+
appState.state = 'show'
|
|
133
185
|
global.__mpxAppLaunched = true
|
|
134
186
|
global.__mpxAppHotLaunched = true
|
|
135
187
|
}
|
|
136
188
|
}
|
|
137
189
|
|
|
138
190
|
useEffect(() => {
|
|
139
|
-
const changeSubscription = ReactNative.AppState.addEventListener('change', (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (navigation) {
|
|
144
|
-
const state = navigation.getState()
|
|
145
|
-
const current = state.routes[state.index]
|
|
146
|
-
options = {
|
|
147
|
-
path: current.name,
|
|
148
|
-
query: current.params,
|
|
149
|
-
scene: 0,
|
|
150
|
-
shareTicket: '',
|
|
151
|
-
referrerInfo: {}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
global.__mpxAppCbs.show.forEach((cb) => {
|
|
155
|
-
cb(options)
|
|
156
|
-
})
|
|
157
|
-
if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
|
|
158
|
-
global.__mpxPageStatusMap[navigation.pageId] = 'show'
|
|
159
|
-
}
|
|
160
|
-
} else if (currentState === 'inactive' || currentState === 'background') {
|
|
161
|
-
global.__mpxAppCbs.hide.forEach((cb) => {
|
|
162
|
-
cb({
|
|
163
|
-
reason: 3
|
|
164
|
-
})
|
|
165
|
-
})
|
|
166
|
-
const navigation = getFocusedNavigation()
|
|
167
|
-
if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
|
|
168
|
-
global.__mpxPageStatusMap[navigation.pageId] = 'hide'
|
|
169
|
-
}
|
|
170
|
-
}
|
|
191
|
+
const changeSubscription = ReactNative.AppState.addEventListener('change', (state) => {
|
|
192
|
+
// 外层可能会异常设置此配置,因此加载监听函数内部
|
|
193
|
+
if (Mpx.config.rnConfig.disableAppStateListener) return
|
|
194
|
+
onAppStateChange(state)
|
|
171
195
|
})
|
|
172
196
|
|
|
173
197
|
let count = 0
|
|
@@ -182,12 +206,8 @@ export default function createApp (options) {
|
|
|
182
206
|
}
|
|
183
207
|
})
|
|
184
208
|
return () => {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
cb({
|
|
188
|
-
reason: 0
|
|
189
|
-
})
|
|
190
|
-
})
|
|
209
|
+
appState.hideReason = 0
|
|
210
|
+
appState.state = 'hide'
|
|
191
211
|
changeSubscription && changeSubscription.remove()
|
|
192
212
|
resizeSubScription && resizeSubScription.remove()
|
|
193
213
|
}
|
|
@@ -195,32 +215,10 @@ export default function createApp (options) {
|
|
|
195
215
|
|
|
196
216
|
const { initialRouteName, initialParams } = initialRouteRef.current
|
|
197
217
|
const navScreenOpts = {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
// 整体切换native-stack时进行修改如下
|
|
203
|
-
// statusBarTranslucent: true,
|
|
204
|
-
// statusBarBackgroundColor: 'transparent'
|
|
205
|
-
}
|
|
206
|
-
if (__mpx_mode__ === 'ios') {
|
|
207
|
-
// ios使用native-stack
|
|
208
|
-
const headerBackImageSource = Mpx.config.rnConfig.headerBackImageSource || null
|
|
209
|
-
if (headerBackImageSource) {
|
|
210
|
-
navScreenOpts.headerBackImageSource = headerBackImageSource
|
|
211
|
-
}
|
|
212
|
-
} else {
|
|
213
|
-
// 安卓上会出现导航条闪现的问题所以默认加headerShown false(stack版本, native-stack版本可以干掉)
|
|
214
|
-
// iOS加上默认headerShown false的话会因为iOS根高度是screenHeight - useHeaderHeight()会导致出现渲染两次情况,因此iOS不加此默认值
|
|
215
|
-
navScreenOpts.headerShown = false
|
|
216
|
-
// 安卓和鸿蒙先用stack
|
|
217
|
-
const headerBackImageProps = Mpx.config.rnConfig.headerBackImageProps || null
|
|
218
|
-
if (headerBackImageProps) {
|
|
219
|
-
navScreenOpts.headerBackImage = () => {
|
|
220
|
-
return createElement(ReactNative.Image, headerBackImageProps)
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
218
|
+
headerShown: false,
|
|
219
|
+
statusBarTranslucent: true,
|
|
220
|
+
statusBarBackgroundColor: 'transparent'
|
|
221
|
+
}
|
|
224
222
|
|
|
225
223
|
return createElement(SafeAreaProvider,
|
|
226
224
|
null,
|
|
@@ -256,4 +254,12 @@ export default function createApp (options) {
|
|
|
256
254
|
global.__mpxPageStatusMap[navigation.pageId] = status
|
|
257
255
|
}
|
|
258
256
|
}
|
|
257
|
+
|
|
258
|
+
// 用于外层业务用来设置App的展示情况
|
|
259
|
+
global.setAppShow = function () {
|
|
260
|
+
onAppStateChange('active')
|
|
261
|
+
}
|
|
262
|
+
global.setAppHide = function () {
|
|
263
|
+
onAppStateChange('inactive')
|
|
264
|
+
}
|
|
259
265
|
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createElement, useState, useMemo } from 'react'
|
|
2
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
3
|
+
import * as ReactNative from 'react-native'
|
|
4
|
+
import Mpx from '../../index'
|
|
5
|
+
|
|
6
|
+
function convertToHex (color) {
|
|
7
|
+
try {
|
|
8
|
+
const intColor = ReactNative.processColor(color)
|
|
9
|
+
if (intColor === null || intColor === undefined) {
|
|
10
|
+
return null
|
|
11
|
+
}
|
|
12
|
+
// 将32位整数颜色值转换为RGBA
|
|
13
|
+
const r = (intColor >> 16) & 255
|
|
14
|
+
const g = (intColor >> 8) & 255
|
|
15
|
+
const b = intColor & 255
|
|
16
|
+
// 转换为十六进制
|
|
17
|
+
const hexR = r.toString(16).padStart(2, '0')
|
|
18
|
+
const hexG = g.toString(16).padStart(2, '0')
|
|
19
|
+
const hexB = b.toString(16).padStart(2, '0')
|
|
20
|
+
return `#${hexR}${hexG}${hexB}`
|
|
21
|
+
} catch (error) {
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const titleHeight = 44
|
|
27
|
+
export function useInnerHeaderHeight (pageconfig) {
|
|
28
|
+
if (pageconfig.navigationStyle === 'custom') {
|
|
29
|
+
return 0
|
|
30
|
+
} else {
|
|
31
|
+
const safeAreaTop = useSafeAreaInsets()?.top || 0
|
|
32
|
+
const headerHeight = safeAreaTop + titleHeight
|
|
33
|
+
return headerHeight
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const styles = ReactNative.StyleSheet.create({
|
|
38
|
+
header: {
|
|
39
|
+
elevation: 3
|
|
40
|
+
},
|
|
41
|
+
headerContent: {
|
|
42
|
+
flexDirection: 'row',
|
|
43
|
+
alignItems: 'center',
|
|
44
|
+
justifyContent: 'center'
|
|
45
|
+
},
|
|
46
|
+
backButton: {
|
|
47
|
+
position: 'absolute',
|
|
48
|
+
height: '100%',
|
|
49
|
+
width: 40,
|
|
50
|
+
left: 0,
|
|
51
|
+
top: 0,
|
|
52
|
+
alignItems: 'center',
|
|
53
|
+
justifyContent: 'center'
|
|
54
|
+
},
|
|
55
|
+
backButtonImage: {
|
|
56
|
+
width: 22,
|
|
57
|
+
height: 22
|
|
58
|
+
},
|
|
59
|
+
title: {
|
|
60
|
+
fontSize: 17,
|
|
61
|
+
fontWeight: 600,
|
|
62
|
+
width: '60%',
|
|
63
|
+
textAlign: 'center'
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
const NavColor = {
|
|
67
|
+
White: '#ffffff',
|
|
68
|
+
Black: '#000000'
|
|
69
|
+
}
|
|
70
|
+
// navigationBarTextStyle只支持黑白'white'/'black
|
|
71
|
+
const validBarTextStyle = (textStyle) => {
|
|
72
|
+
const textStyleColor = convertToHex(textStyle)
|
|
73
|
+
if (textStyle && [NavColor.White, NavColor.Black].includes(textStyleColor)) {
|
|
74
|
+
return textStyleColor
|
|
75
|
+
} else {
|
|
76
|
+
return NavColor.White
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export function innerNav ({ props, navigation }) {
|
|
80
|
+
const { pageConfig } = props
|
|
81
|
+
const [innerPageConfig, setPageConfig] = useState(pageConfig || {})
|
|
82
|
+
navigation.setPageConfig = (config) => {
|
|
83
|
+
const newConfig = Object.assign({}, innerPageConfig, config)
|
|
84
|
+
setPageConfig(newConfig)
|
|
85
|
+
}
|
|
86
|
+
const isCustom = innerPageConfig.navigationStyle === 'custom'
|
|
87
|
+
const navigationBarTextStyle = useMemo(() => validBarTextStyle(innerPageConfig.navigationBarTextStyle), [innerPageConfig.navigationBarTextStyle])
|
|
88
|
+
// 状态栏的颜色
|
|
89
|
+
const statusBarElement = createElement(ReactNative.StatusBar, {
|
|
90
|
+
translucent: true,
|
|
91
|
+
backgroundColor: 'transparent',
|
|
92
|
+
barStyle: (navigationBarTextStyle === NavColor.White) ? 'light-content' : 'dark-content' // 'default'/'light-content'/'dark-content'
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
if (isCustom) return statusBarElement
|
|
96
|
+
const safeAreaTop = useSafeAreaInsets()?.top || 0
|
|
97
|
+
// 假设是栈导航,获取栈的长度
|
|
98
|
+
const stackLength = navigation.getState()?.routes?.length
|
|
99
|
+
// 用于外部注册打开RN容器之前的栈长度
|
|
100
|
+
const beforeStackLength = Mpx.config?.rnConfig?.beforeStackLength || 0
|
|
101
|
+
|
|
102
|
+
// 回退按钮与图标
|
|
103
|
+
const backElement = stackLength + beforeStackLength > 1
|
|
104
|
+
? createElement(ReactNative.TouchableOpacity, {
|
|
105
|
+
style: [styles.backButton],
|
|
106
|
+
onPress: () => { navigation.goBack() }
|
|
107
|
+
}, createElement(ReactNative.Image, {
|
|
108
|
+
source: { uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAABICAYAAACqT5alAAAA2UlEQVR4nO3bMQrCUBRE0Yla6AYEN2nnBrTL+izcitW3MRDkEUWSvPzJvfCqgMwhZbAppWhNbbIHzB1g9wATERFRVyvpkj1irlpJ5X326D7WHh1hbdFD2CLpLmmftm7kfsEe09aNHFiBrT+wAlt/YAW2/sAKbP2BFdj6Ayuwy+ufz6XPL893krZ//O6iu2n4LT8kndLWTRTo4EC7BDo40C6BDg60S6CDA+0S6OBAuwQ6uNWiD2nrJmoIfU7cNWkR2hbb1UfbY7uuWhGWiIg+a/iHuHmA3QPs3gu4JW9Gan+OJAAAAABJRU5ErkJggg==' },
|
|
109
|
+
// 回退按钮的颜色与设置的title文案颜色一致
|
|
110
|
+
style: [styles.backButtonImage, { tintColor: navigationBarTextStyle }]
|
|
111
|
+
}))
|
|
112
|
+
: null
|
|
113
|
+
|
|
114
|
+
return createElement(ReactNative.View, {
|
|
115
|
+
style: [styles.header, {
|
|
116
|
+
paddingTop: safeAreaTop,
|
|
117
|
+
backgroundColor: innerPageConfig.navigationBarBackgroundColor || '#000000'
|
|
118
|
+
}]
|
|
119
|
+
},
|
|
120
|
+
statusBarElement,
|
|
121
|
+
createElement(ReactNative.View, {
|
|
122
|
+
style: styles.headerContent,
|
|
123
|
+
height: titleHeight
|
|
124
|
+
}, backElement,
|
|
125
|
+
createElement(ReactNative.Text, {
|
|
126
|
+
style: [styles.title, { color: navigationBarTextStyle }],
|
|
127
|
+
numberOfLines: 1
|
|
128
|
+
}, innerPageConfig.navigationBarTitleText?.trim() || ''))
|
|
129
|
+
)
|
|
130
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
|
2
2
|
import { NavigationContainer, StackActions } from '@react-navigation/native'
|
|
3
3
|
import PortalHost from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal/portal-host'
|
|
4
4
|
import { useHeaderHeight } from '@react-navigation/elements'
|
|
@@ -6,7 +6,7 @@ import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-cont
|
|
|
6
6
|
import { GestureHandlerRootView } from 'react-native-gesture-handler'
|
|
7
7
|
|
|
8
8
|
export {
|
|
9
|
-
|
|
9
|
+
createNativeStackNavigator,
|
|
10
10
|
NavigationContainer,
|
|
11
11
|
useHeaderHeight,
|
|
12
12
|
StackActions,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createNativeStackNavigator
|
|
1
|
+
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
|
2
2
|
import { NavigationContainer, StackActions } from '@react-navigation/native'
|
|
3
3
|
import PortalHost from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal/portal-host'
|
|
4
4
|
import { useHeaderHeight } from '@react-navigation/elements'
|
|
@@ -6,7 +6,7 @@ import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-cont
|
|
|
6
6
|
import { GestureHandlerRootView } from 'react-native-gesture-handler'
|
|
7
7
|
|
|
8
8
|
export {
|
|
9
|
-
|
|
9
|
+
createNativeStackNavigator,
|
|
10
10
|
NavigationContainer,
|
|
11
11
|
useHeaderHeight,
|
|
12
12
|
StackActions,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect,
|
|
1
|
+
import { useEffect, useSyncExternalStore, useRef, useMemo, createElement, memo, forwardRef, useImperativeHandle, useContext, Fragment, cloneElement, createContext } from 'react'
|
|
2
2
|
import * as ReactNative from 'react-native'
|
|
3
3
|
import { ReactiveEffect } from '../../observer/effect'
|
|
4
4
|
import { watch } from '../../observer/watch'
|
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
KeyboardAvoidContext,
|
|
16
16
|
RouteContext
|
|
17
17
|
} from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/context'
|
|
18
|
-
import { PortalHost, useSafeAreaInsets, GestureHandlerRootView
|
|
18
|
+
import { PortalHost, useSafeAreaInsets, GestureHandlerRootView } from '../env/navigationHelper'
|
|
19
|
+
import { innerNav, useInnerHeaderHeight } from '../env/nav'
|
|
19
20
|
|
|
20
21
|
const ProviderContext = createContext(null)
|
|
21
22
|
function getSystemInfo () {
|
|
@@ -392,7 +393,7 @@ function usePageEffect (mpxProxy, pageId) {
|
|
|
392
393
|
} else if (/^resize/.test(newVal)) {
|
|
393
394
|
triggerResizeEvent(mpxProxy)
|
|
394
395
|
}
|
|
395
|
-
})
|
|
396
|
+
}, { sync: true })
|
|
396
397
|
}
|
|
397
398
|
}
|
|
398
399
|
return () => {
|
|
@@ -445,11 +446,30 @@ const checkRelation = (options) => {
|
|
|
445
446
|
hasAncestorRelation
|
|
446
447
|
}
|
|
447
448
|
}
|
|
449
|
+
function getLayoutData (headerHeight) {
|
|
450
|
+
const screenDimensions = ReactNative.Dimensions.get('screen')
|
|
451
|
+
const windowDimensions = ReactNative.Dimensions.get('window')
|
|
452
|
+
// 在横屏状态下 screen.height = window.height + bottomVirtualHeight
|
|
453
|
+
// 在正常状态 screen.height = window.height + bottomVirtualHeight + statusBarHeight
|
|
454
|
+
const isLandscape = screenDimensions.height < screenDimensions.width
|
|
455
|
+
const bottomVirtualHeight = isLandscape ? screenDimensions.height - windowDimensions.height : ((screenDimensions.height - windowDimensions.height - ReactNative.StatusBar.currentHeight) || 0)
|
|
456
|
+
return {
|
|
457
|
+
x: 0,
|
|
458
|
+
y: headerHeight,
|
|
459
|
+
left: 0,
|
|
460
|
+
top: headerHeight,
|
|
461
|
+
// 此处必须为windowDimensions.width,在横屏状态下windowDimensions.width才符合预期
|
|
462
|
+
width: windowDimensions.width,
|
|
463
|
+
height: screenDimensions.height - headerHeight - bottomVirtualHeight,
|
|
464
|
+
// ios为0 android为实际statusbar高度
|
|
465
|
+
statusBarHeight: ReactNative.StatusBar.currentHeight || 0,
|
|
466
|
+
bottomVirtualHeight: bottomVirtualHeight,
|
|
467
|
+
isLandscape: isLandscape
|
|
468
|
+
}
|
|
469
|
+
}
|
|
448
470
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
export function PageWrapperHOC (WrappedComponent) {
|
|
452
|
-
return function PageWrapperCom ({ navigation, route, pageConfig = {}, ...props }) {
|
|
471
|
+
export function PageWrapperHOC (WrappedComponent, pageConfig = {}) {
|
|
472
|
+
return function PageWrapperCom ({ navigation, route, ...props }) {
|
|
453
473
|
const rootRef = useRef(null)
|
|
454
474
|
const keyboardAvoidRef = useRef(null)
|
|
455
475
|
const intersectionObservers = useRef({})
|
|
@@ -464,59 +484,15 @@ export function PageWrapperHOC (WrappedComponent) {
|
|
|
464
484
|
error('Using pageWrapper requires passing navigation and route')
|
|
465
485
|
return null
|
|
466
486
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
navigation.setOptions({
|
|
470
|
-
title: currentPageConfig.navigationBarTitleText?.trim() || '',
|
|
471
|
-
headerStyle: {
|
|
472
|
-
backgroundColor: currentPageConfig.navigationBarBackgroundColor || '#000000'
|
|
473
|
-
},
|
|
474
|
-
headerTintColor: currentPageConfig.navigationBarTextStyle || 'white'
|
|
475
|
-
})
|
|
476
|
-
|
|
477
|
-
// TODO 此部分内容在native-stack可删除,用setOptions设置
|
|
478
|
-
if (__mpx_mode__ !== 'ios') {
|
|
479
|
-
ReactNative.StatusBar.setBarStyle(currentPageConfig.barStyle || 'dark-content')
|
|
480
|
-
ReactNative.StatusBar.setTranslucent(true) // 控制statusbar是否占位
|
|
481
|
-
ReactNative.StatusBar.setBackgroundColor('transparent')
|
|
482
|
-
}
|
|
483
|
-
}, [])
|
|
484
|
-
|
|
485
|
-
const headerHeight = useHeaderHeight()
|
|
487
|
+
const headerHeight = useInnerHeaderHeight(currentPageConfig)
|
|
488
|
+
navigation.layout = getLayoutData(headerHeight)
|
|
486
489
|
const onLayout = () => {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
navigation.layout = {
|
|
490
|
-
x: 0,
|
|
491
|
-
y: headerHeight,
|
|
492
|
-
width: screenDimensions.width,
|
|
493
|
-
height: screenDimensions.height - headerHeight
|
|
494
|
-
}
|
|
495
|
-
} else {
|
|
496
|
-
if (bottomVirtualHeight === null) {
|
|
497
|
-
rootRef.current?.measureInWindow((x, y, width, height) => {
|
|
498
|
-
// 沉浸模式的计算方式
|
|
499
|
-
bottomVirtualHeight = screenDimensions.height - height - headerHeight
|
|
500
|
-
// 非沉浸模式(translucent=true)计算方式, 现在默认是全用沉浸模式,所以先不算这个
|
|
501
|
-
// bottomVirtualHeight = windowDimensions.height - height - headerHeight
|
|
502
|
-
navigation.layout = {
|
|
503
|
-
x: 0,
|
|
504
|
-
y: headerHeight,
|
|
505
|
-
width: screenDimensions.width,
|
|
506
|
-
height: height
|
|
507
|
-
}
|
|
508
|
-
})
|
|
509
|
-
} else {
|
|
510
|
-
navigation.layout = {
|
|
511
|
-
x: 0,
|
|
512
|
-
y: headerHeight, // 这个y值
|
|
513
|
-
width: screenDimensions.width,
|
|
514
|
-
// 后续页面的layout是通过第一次路由进入时候推算出来的底部区域来推算出来的
|
|
515
|
-
height: screenDimensions.height - bottomVirtualHeight - headerHeight
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
}
|
|
490
|
+
// 当用户处于横屏或者竖屏状态的时候,需要进行layout修正
|
|
491
|
+
navigation.layout = getLayoutData(headerHeight)
|
|
519
492
|
}
|
|
493
|
+
|
|
494
|
+
usePageStatus(navigation, currentPageId)
|
|
495
|
+
|
|
520
496
|
const withKeyboardAvoidingView = (element) => {
|
|
521
497
|
return createElement(KeyboardAvoidContext.Provider,
|
|
522
498
|
{
|
|
@@ -535,26 +511,26 @@ export function PageWrapperHOC (WrappedComponent) {
|
|
|
535
511
|
)
|
|
536
512
|
)
|
|
537
513
|
}
|
|
538
|
-
|
|
514
|
+
// android存在第一次打开insets都返回为0情况,后续会触发第二次渲染后正确
|
|
539
515
|
navigation.insets = useSafeAreaInsets()
|
|
540
|
-
|
|
541
516
|
return createElement(GestureHandlerRootView,
|
|
542
517
|
{
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
height: ReactNative.Dimensions.get('screen').height - useHeaderHeight()
|
|
547
|
-
}
|
|
548
|
-
: {
|
|
549
|
-
flex: 1
|
|
550
|
-
}
|
|
518
|
+
style: {
|
|
519
|
+
flex: 1
|
|
520
|
+
}
|
|
551
521
|
},
|
|
522
|
+
createElement(innerNav, {
|
|
523
|
+
props: { pageConfig: currentPageConfig },
|
|
524
|
+
navigation
|
|
525
|
+
}),
|
|
552
526
|
withKeyboardAvoidingView(
|
|
553
527
|
createElement(ReactNative.View,
|
|
554
528
|
{
|
|
555
529
|
style: {
|
|
556
530
|
flex: 1,
|
|
557
|
-
backgroundColor: currentPageConfig?.backgroundColor || '#fff'
|
|
531
|
+
backgroundColor: currentPageConfig?.backgroundColor || '#fff',
|
|
532
|
+
// 解决页面内有元素定位relative left为负值的时候,回退的时候还能看到对应元素问题
|
|
533
|
+
overflow: 'hidden'
|
|
558
534
|
},
|
|
559
535
|
ref: rootRef,
|
|
560
536
|
onLayout
|
|
@@ -582,7 +558,6 @@ export function PageWrapperHOC (WrappedComponent) {
|
|
|
582
558
|
))
|
|
583
559
|
}
|
|
584
560
|
}
|
|
585
|
-
|
|
586
561
|
export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
|
|
587
562
|
rawOptions = mergeOptions(rawOptions, type, false)
|
|
588
563
|
const components = Object.assign({}, rawOptions.components, currentInject.getComponents())
|
|
@@ -656,8 +631,13 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
|
|
|
656
631
|
return () => {
|
|
657
632
|
proxy.unmounted()
|
|
658
633
|
proxy.target.__resetInstance()
|
|
634
|
+
// 热更新下会销毁旧页面并创建新页面组件,且旧页面组件销毁时机晚于新页面组件创建,此时__mpxPagesMap中存储的为新页面组件,不应该删除
|
|
635
|
+
// 所以需要判断路由表中存储的页面实例是否为当前页面实例
|
|
659
636
|
if (type === 'page') {
|
|
660
|
-
|
|
637
|
+
const routeKey = props.route.key
|
|
638
|
+
if (global.__mpxPagesMap[routeKey] && global.__mpxPagesMap[routeKey][0] === instance) {
|
|
639
|
+
delete global.__mpxPagesMap[routeKey]
|
|
640
|
+
}
|
|
661
641
|
}
|
|
662
642
|
}
|
|
663
643
|
}, [])
|
|
@@ -718,11 +698,7 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
|
|
|
718
698
|
}
|
|
719
699
|
|
|
720
700
|
if (type === 'page') {
|
|
721
|
-
return (
|
|
722
|
-
createElement(PageWrapperHOC(defaultOptions), {
|
|
723
|
-
pageConfig: currentInject.pageConfig,
|
|
724
|
-
...props
|
|
725
|
-
})
|
|
701
|
+
return PageWrapperHOC(defaultOptions, currentInject.pageConfig)
|
|
726
702
|
}
|
|
727
703
|
return defaultOptions
|
|
728
704
|
}
|