@mpxjs/core 2.10.6-beta.1 → 2.10.6-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -9,7 +9,8 @@ import { watch } from '../observer/watch'
|
|
|
9
9
|
import { createElement, memo, useRef, useEffect } from 'react'
|
|
10
10
|
import * as ReactNative from 'react-native'
|
|
11
11
|
import { initAppProvides } from './export/inject'
|
|
12
|
-
import { NavigationContainer, createNativeStackNavigator, SafeAreaProvider } from './env/navigationHelper'
|
|
12
|
+
import { NavigationContainer, createNativeStackNavigator, SafeAreaProvider, GestureHandlerRootView } from './env/navigationHelper'
|
|
13
|
+
import { innerNav } from './env/nav'
|
|
13
14
|
|
|
14
15
|
const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
|
|
15
16
|
|
|
@@ -55,23 +56,40 @@ export default function createApp (options) {
|
|
|
55
56
|
const pages = currentInject.getPages() || {}
|
|
56
57
|
const firstPage = currentInject.firstPage
|
|
57
58
|
const Stack = createNativeStackNavigator()
|
|
59
|
+
const withHeader = (wrappedComponent, { pageConfig = {} }) => {
|
|
60
|
+
return ({ navigation, ...props }) => {
|
|
61
|
+
return createElement(GestureHandlerRootView,
|
|
62
|
+
{
|
|
63
|
+
style: {
|
|
64
|
+
flex: 1
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
createElement(innerNav, {
|
|
68
|
+
pageConfig: pageConfig,
|
|
69
|
+
navigation
|
|
70
|
+
}),
|
|
71
|
+
createElement(wrappedComponent, { navigation, ...props })
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
58
75
|
const getPageScreens = (initialRouteName, initialParams) => {
|
|
59
76
|
return Object.entries(pages).map(([key, item]) => {
|
|
60
77
|
// const options = {
|
|
61
78
|
// // __mpxPageStatusMap 为编译注入的全局变量
|
|
62
79
|
// headerShown: !(Object.assign({}, global.__mpxPageConfig, global.__mpxPageConfigsMap[key]).navigationStyle === 'custom')
|
|
63
80
|
// }
|
|
81
|
+
const pageConfig = Object.assign({}, global.__mpxPageConfig, global.__mpxPageConfigsMap[key])
|
|
64
82
|
if (key === initialRouteName) {
|
|
65
83
|
return createElement(Stack.Screen, {
|
|
66
84
|
name: key,
|
|
67
|
-
component: item,
|
|
85
|
+
component: withHeader(item, { pageConfig }),
|
|
68
86
|
initialParams
|
|
69
87
|
// options
|
|
70
88
|
})
|
|
71
89
|
}
|
|
72
90
|
return createElement(Stack.Screen, {
|
|
73
91
|
name: key,
|
|
74
|
-
component: item
|
|
92
|
+
component: withHeader(item, { pageConfig })
|
|
75
93
|
// options
|
|
76
94
|
})
|
|
77
95
|
})
|
|
@@ -10,13 +10,15 @@ export function init (Mpx) {
|
|
|
10
10
|
show: [],
|
|
11
11
|
hide: [],
|
|
12
12
|
error: [],
|
|
13
|
-
rejection: []
|
|
13
|
+
rejection: [],
|
|
14
|
+
lazyLoad: []
|
|
14
15
|
}
|
|
15
16
|
global.__navigationHelper = navigationHelper
|
|
16
17
|
if (global.i18n) {
|
|
17
18
|
Mpx.i18n = createI18n(global.i18n)
|
|
18
19
|
}
|
|
19
20
|
initGlobalErrorHandling()
|
|
21
|
+
initGlobalLazyLoadHandling()
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
function initGlobalErrorHandling () {
|
|
@@ -63,3 +65,13 @@ function initGlobalErrorHandling () {
|
|
|
63
65
|
require('promise/setimmediate/rejection-tracking').enable(rejectionTrackingOptions)
|
|
64
66
|
}
|
|
65
67
|
}
|
|
68
|
+
|
|
69
|
+
function initGlobalLazyLoadHandling () {
|
|
70
|
+
global.onLazyLoadError = function (error) {
|
|
71
|
+
if (global.__mpxAppCbs?.lazyLoad?.length) {
|
|
72
|
+
global.__mpxAppCbs.lazyLoad.forEach((cb) => {
|
|
73
|
+
cb(error)
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
package/src/platform/env/nav.js
CHANGED
|
@@ -1,36 +1,40 @@
|
|
|
1
1
|
import { createElement, useState, useMemo } from 'react'
|
|
2
2
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
3
|
-
import
|
|
3
|
+
import { StatusBar, processColor, TouchableOpacity, Image, View, StyleSheet, Text } from 'react-native'
|
|
4
4
|
import Mpx from '../../index'
|
|
5
5
|
|
|
6
|
+
function convertToHex (color) {
|
|
7
|
+
try {
|
|
8
|
+
const intColor = 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
|
|
6
27
|
export function useInnerHeaderHeight (pageconfig) {
|
|
7
28
|
if (pageconfig.navigationStyle === 'custom') {
|
|
8
29
|
return 0
|
|
9
30
|
} else {
|
|
10
31
|
const safeAreaTop = useSafeAreaInsets()?.top || 0
|
|
11
|
-
const headerHeight = safeAreaTop +
|
|
32
|
+
const headerHeight = safeAreaTop + titleHeight
|
|
12
33
|
return headerHeight
|
|
13
34
|
}
|
|
14
35
|
}
|
|
15
36
|
|
|
16
|
-
|
|
17
|
-
function getTitleHeight () {
|
|
18
|
-
return 44
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// 计算颜色亮度
|
|
22
|
-
const getColorBrightness = (color) => {
|
|
23
|
-
const processedColor = ReactNative.processColor(color)
|
|
24
|
-
if (typeof processedColor === 'number') {
|
|
25
|
-
const r = (processedColor >> 16) & 255
|
|
26
|
-
const g = (processedColor >> 8) & 255
|
|
27
|
-
const b = processedColor & 255
|
|
28
|
-
return (r * 299 + g * 587 + b * 114) / 1000
|
|
29
|
-
}
|
|
30
|
-
return 0
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const styles = ReactNative.StyleSheet.create({
|
|
37
|
+
const styles = StyleSheet.create({
|
|
34
38
|
header: {
|
|
35
39
|
elevation: 3
|
|
36
40
|
},
|
|
@@ -54,27 +58,41 @@ const styles = ReactNative.StyleSheet.create({
|
|
|
54
58
|
},
|
|
55
59
|
title: {
|
|
56
60
|
fontSize: 17,
|
|
57
|
-
fontWeight: 600
|
|
61
|
+
fontWeight: 600,
|
|
62
|
+
width: '60%',
|
|
63
|
+
textAlign: 'center'
|
|
58
64
|
}
|
|
59
65
|
})
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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 ({ pageConfig, navigation }) {
|
|
63
80
|
const [innerPageConfig, setPageConfig] = useState(pageConfig || {})
|
|
64
81
|
navigation.setPageConfig = (config) => {
|
|
65
82
|
const newConfig = Object.assign({}, innerPageConfig, config)
|
|
66
83
|
setPageConfig(newConfig)
|
|
67
84
|
}
|
|
68
|
-
|
|
69
85
|
const isCustom = innerPageConfig.navigationStyle === 'custom'
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
86
|
+
const navigationBarTextStyle = useMemo(() => validBarTextStyle(innerPageConfig.navigationBarTextStyle), [innerPageConfig.navigationBarTextStyle])
|
|
87
|
+
// 状态栏的颜色
|
|
88
|
+
const statusBarElement = createElement(StatusBar, {
|
|
89
|
+
translucent: true,
|
|
90
|
+
backgroundColor: 'transparent',
|
|
91
|
+
barStyle: (navigationBarTextStyle === NavColor.White) ? 'light-content' : 'dark-content' // 'default'/'light-content'/'dark-content'
|
|
92
|
+
})
|
|
77
93
|
|
|
94
|
+
if (isCustom) return statusBarElement
|
|
95
|
+
const safeAreaTop = useSafeAreaInsets()?.top || 0
|
|
78
96
|
// 假设是栈导航,获取栈的长度
|
|
79
97
|
const stackLength = navigation.getState()?.routes?.length
|
|
80
98
|
// 用于外部注册打开RN容器之前的栈长度
|
|
@@ -82,27 +100,30 @@ export function innerNav ({ props, navigation }) {
|
|
|
82
100
|
|
|
83
101
|
// 回退按钮与图标
|
|
84
102
|
const backElement = stackLength + beforeStackLength > 1
|
|
85
|
-
? createElement(
|
|
103
|
+
? createElement(TouchableOpacity, {
|
|
86
104
|
style: [styles.backButton],
|
|
87
105
|
onPress: () => { navigation.goBack() }
|
|
88
|
-
}, createElement(
|
|
106
|
+
}, createElement(Image, {
|
|
89
107
|
source: { uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAABICAYAAACqT5alAAAA2UlEQVR4nO3bMQrCUBRE0Yla6AYEN2nnBrTL+izcitW3MRDkEUWSvPzJvfCqgMwhZbAppWhNbbIHzB1g9wATERFRVyvpkj1irlpJ5X326D7WHh1hbdFD2CLpLmmftm7kfsEe09aNHFiBrT+wAlt/YAW2/sAKbP2BFdj6Ayuwy+ufz6XPL893krZ//O6iu2n4LT8kndLWTRTo4EC7BDo40C6BDg60S6CDA+0S6OBAuwQ6uNWiD2nrJmoIfU7cNWkR2hbb1UfbY7uuWhGWiIg+a/iHuHmA3QPs3gu4JW9Gan+OJAAAAABJRU5ErkJggg==' },
|
|
90
|
-
|
|
108
|
+
// 回退按钮的颜色与设置的title文案颜色一致
|
|
109
|
+
style: [styles.backButtonImage, { tintColor: navigationBarTextStyle }]
|
|
91
110
|
}))
|
|
92
111
|
: null
|
|
93
112
|
|
|
94
|
-
return createElement(
|
|
113
|
+
return createElement(View, {
|
|
95
114
|
style: [styles.header, {
|
|
96
115
|
paddingTop: safeAreaTop,
|
|
97
116
|
backgroundColor: innerPageConfig.navigationBarBackgroundColor || '#000000'
|
|
98
117
|
}]
|
|
99
118
|
},
|
|
100
|
-
|
|
119
|
+
statusBarElement,
|
|
120
|
+
createElement(View, {
|
|
101
121
|
style: styles.headerContent,
|
|
102
|
-
height:
|
|
122
|
+
height: titleHeight
|
|
103
123
|
}, backElement,
|
|
104
|
-
createElement(
|
|
105
|
-
style: [styles.title, { color:
|
|
124
|
+
createElement(Text, {
|
|
125
|
+
style: [styles.title, { color: navigationBarTextStyle }],
|
|
126
|
+
numberOfLines: 1
|
|
106
127
|
}, innerPageConfig.navigationBarTitleText?.trim() || ''))
|
|
107
128
|
)
|
|
108
129
|
}
|
|
@@ -15,8 +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
|
|
19
|
-
import {
|
|
18
|
+
import { PortalHost, useSafeAreaInsets } from '../env/navigationHelper'
|
|
19
|
+
import { useInnerHeaderHeight } from '../env/nav'
|
|
20
20
|
|
|
21
21
|
const ProviderContext = createContext(null)
|
|
22
22
|
function getSystemInfo () {
|
|
@@ -419,6 +419,22 @@ function usePageStatus (navigation, pageId) {
|
|
|
419
419
|
}, [navigation])
|
|
420
420
|
}
|
|
421
421
|
|
|
422
|
+
function usePagePreload (route) {
|
|
423
|
+
const name = route.name
|
|
424
|
+
useEffect(() => {
|
|
425
|
+
setTimeout(() => {
|
|
426
|
+
const preloadRule = global.__preloadRule || {}
|
|
427
|
+
const { packages } = preloadRule[name] || {}
|
|
428
|
+
if (packages?.length > 0) {
|
|
429
|
+
const downloadChunkAsync = mpxGlobal.__mpx.config?.rnConfig?.downloadChunkAsync
|
|
430
|
+
if (typeof downloadChunkAsync === 'function') {
|
|
431
|
+
callWithErrorHandling(() => downloadChunkAsync(packages))
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}, 800)
|
|
435
|
+
}, [])
|
|
436
|
+
}
|
|
437
|
+
|
|
422
438
|
const RelationsContext = createContext(null)
|
|
423
439
|
|
|
424
440
|
const checkRelation = (options) => {
|
|
@@ -447,8 +463,6 @@ function getLayoutData (headerHeight) {
|
|
|
447
463
|
const isLandscape = screenDimensions.height < screenDimensions.width
|
|
448
464
|
const bottomVirtualHeight = isLandscape ? screenDimensions.height - windowDimensions.height : ((screenDimensions.height - windowDimensions.height - ReactNative.StatusBar.currentHeight) || 0)
|
|
449
465
|
return {
|
|
450
|
-
x: 0,
|
|
451
|
-
y: headerHeight,
|
|
452
466
|
left: 0,
|
|
453
467
|
top: headerHeight,
|
|
454
468
|
// 此处必须为windowDimensions.width,在横屏状态下windowDimensions.width才符合预期
|
|
@@ -461,8 +475,8 @@ function getLayoutData (headerHeight) {
|
|
|
461
475
|
}
|
|
462
476
|
}
|
|
463
477
|
|
|
464
|
-
export function PageWrapperHOC (WrappedComponent) {
|
|
465
|
-
return function PageWrapperCom ({ navigation, route,
|
|
478
|
+
export function PageWrapperHOC (WrappedComponent, pageConfig = {}) {
|
|
479
|
+
return function PageWrapperCom ({ navigation, route, ...props }) {
|
|
466
480
|
const rootRef = useRef(null)
|
|
467
481
|
const keyboardAvoidRef = useRef(null)
|
|
468
482
|
const intersectionObservers = useRef({})
|
|
@@ -479,11 +493,15 @@ export function PageWrapperHOC (WrappedComponent) {
|
|
|
479
493
|
}
|
|
480
494
|
const headerHeight = useInnerHeaderHeight(currentPageConfig)
|
|
481
495
|
navigation.layout = getLayoutData(headerHeight)
|
|
482
|
-
const onLayout = () => {
|
|
483
|
-
// 当用户处于横屏或者竖屏状态的时候,需要进行layout修正
|
|
484
|
-
navigation.layout = getLayoutData(headerHeight)
|
|
485
|
-
}
|
|
486
496
|
|
|
497
|
+
useEffect(() => {
|
|
498
|
+
const dimensionListener = ReactNative.Dimensions.addEventListener('change', ({ screen }) => {
|
|
499
|
+
navigation.layout = getLayoutData(headerHeight)
|
|
500
|
+
})
|
|
501
|
+
return () => dimensionListener?.remove()
|
|
502
|
+
}, [])
|
|
503
|
+
|
|
504
|
+
usePagePreload(route)
|
|
487
505
|
usePageStatus(navigation, currentPageId)
|
|
488
506
|
|
|
489
507
|
const withKeyboardAvoidingView = (element) => {
|
|
@@ -506,49 +524,38 @@ export function PageWrapperHOC (WrappedComponent) {
|
|
|
506
524
|
}
|
|
507
525
|
// android存在第一次打开insets都返回为0情况,后续会触发第二次渲染后正确
|
|
508
526
|
navigation.insets = useSafeAreaInsets()
|
|
509
|
-
return
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
createElement(
|
|
527
|
+
return withKeyboardAvoidingView(
|
|
528
|
+
createElement(ReactNative.View,
|
|
529
|
+
{
|
|
530
|
+
style: {
|
|
531
|
+
flex: 1,
|
|
532
|
+
backgroundColor: currentPageConfig?.backgroundColor || '#fff',
|
|
533
|
+
// 解决页面内有元素定位relative left为负值的时候,回退的时候还能看到对应元素问题
|
|
534
|
+
overflow: 'hidden'
|
|
535
|
+
},
|
|
536
|
+
ref: rootRef
|
|
537
|
+
},
|
|
538
|
+
createElement(RouteContext.Provider,
|
|
521
539
|
{
|
|
522
|
-
|
|
523
|
-
flex: 1,
|
|
524
|
-
backgroundColor: currentPageConfig?.backgroundColor || '#fff',
|
|
525
|
-
// 解决页面内有元素定位relative left为负值的时候,回退的时候还能看到对应元素问题
|
|
526
|
-
overflow: 'hidden'
|
|
527
|
-
},
|
|
528
|
-
ref: rootRef,
|
|
529
|
-
onLayout
|
|
540
|
+
value: routeContextValRef.current
|
|
530
541
|
},
|
|
531
|
-
createElement(
|
|
542
|
+
createElement(IntersectionObserverContext.Provider,
|
|
532
543
|
{
|
|
533
|
-
value:
|
|
544
|
+
value: intersectionObservers.current
|
|
534
545
|
},
|
|
535
|
-
createElement(
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
navigation,
|
|
544
|
-
route,
|
|
545
|
-
id: currentPageId
|
|
546
|
-
})
|
|
547
|
-
)
|
|
546
|
+
createElement(PortalHost,
|
|
547
|
+
null,
|
|
548
|
+
createElement(WrappedComponent, {
|
|
549
|
+
...props,
|
|
550
|
+
navigation,
|
|
551
|
+
route,
|
|
552
|
+
id: currentPageId
|
|
553
|
+
})
|
|
548
554
|
)
|
|
549
555
|
)
|
|
550
556
|
)
|
|
551
|
-
)
|
|
557
|
+
)
|
|
558
|
+
)
|
|
552
559
|
}
|
|
553
560
|
}
|
|
554
561
|
export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
|
|
@@ -618,7 +625,6 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
|
|
|
618
625
|
})
|
|
619
626
|
|
|
620
627
|
usePageEffect(proxy, pageId)
|
|
621
|
-
|
|
622
628
|
useEffect(() => {
|
|
623
629
|
proxy.mounted()
|
|
624
630
|
return () => {
|
|
@@ -691,11 +697,7 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
|
|
|
691
697
|
}
|
|
692
698
|
|
|
693
699
|
if (type === 'page') {
|
|
694
|
-
return (
|
|
695
|
-
createElement(PageWrapperHOC(defaultOptions), {
|
|
696
|
-
pageConfig: currentInject.pageConfig,
|
|
697
|
-
...props
|
|
698
|
-
})
|
|
700
|
+
return PageWrapperHOC(defaultOptions, currentInject.pageConfig)
|
|
699
701
|
}
|
|
700
702
|
return defaultOptions
|
|
701
703
|
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { createNativeStackNavigator } from '@react-navigation/native-stack'
|
|
2
|
-
import { NavigationContainer, StackActions } from '@react-navigation/native'
|
|
3
|
-
import PortalHost from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal/portal-host'
|
|
4
|
-
import { useHeaderHeight } from '@react-navigation/elements'
|
|
5
|
-
import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
6
|
-
import { GestureHandlerRootView } from 'react-native-gesture-handler'
|
|
7
|
-
|
|
8
|
-
export {
|
|
9
|
-
createNativeStackNavigator,
|
|
10
|
-
NavigationContainer,
|
|
11
|
-
useHeaderHeight,
|
|
12
|
-
StackActions,
|
|
13
|
-
GestureHandlerRootView,
|
|
14
|
-
PortalHost,
|
|
15
|
-
SafeAreaProvider,
|
|
16
|
-
useSafeAreaInsets
|
|
17
|
-
}
|