@mpxjs/core 2.10.4-beta.2 → 2.10.4-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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/core",
3
- "version": "2.10.4-beta.2",
3
+ "version": "2.10.4-beta.3",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
@@ -7,7 +7,7 @@ import Mpx from '../index'
7
7
  import { createElement, memo, useRef, useEffect } from 'react'
8
8
  import * as ReactNative from 'react-native'
9
9
  import { initAppProvides } from './export/inject'
10
- import { NavigationContainer, createStackNavigator, SafeAreaProvider } from './env/navigationHelper'
10
+ import { NavigationContainer, createNativeStackNavigator, SafeAreaProvider } from './env/navigationHelper'
11
11
 
12
12
  const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
13
13
 
@@ -52,25 +52,25 @@ export default function createApp (options) {
52
52
 
53
53
  const pages = currentInject.getPages() || {}
54
54
  const firstPage = currentInject.firstPage
55
- const Stack = createStackNavigator()
55
+ const Stack = createNativeStackNavigator()
56
56
  const getPageScreens = (initialRouteName, initialParams) => {
57
57
  return Object.entries(pages).map(([key, item]) => {
58
- const options = {
59
- // __mpxPageStatusMap 为编译注入的全局变量
60
- headerShown: !(Object.assign({}, global.__mpxPageConfig, global.__mpxPageConfigsMap[key]).navigationStyle === 'custom')
61
- }
58
+ // const options = {
59
+ // // __mpxPageStatusMap 为编译注入的全局变量
60
+ // headerShown: !(Object.assign({}, global.__mpxPageConfig, global.__mpxPageConfigsMap[key]).navigationStyle === 'custom')
61
+ // }
62
62
  if (key === initialRouteName) {
63
63
  return createElement(Stack.Screen, {
64
64
  name: key,
65
65
  component: item,
66
- initialParams,
67
- options
66
+ initialParams
67
+ // options
68
68
  })
69
69
  }
70
70
  return createElement(Stack.Screen, {
71
71
  name: key,
72
- component: item,
73
- options
72
+ component: item
73
+ // options
74
74
  })
75
75
  })
76
76
  }
@@ -195,32 +195,10 @@ export default function createApp (options) {
195
195
 
196
196
  const { initialRouteName, initialParams } = initialRouteRef.current
197
197
  const navScreenOpts = {
198
- // 7.x替换headerBackTitleVisible
199
- // headerBackButtonDisplayMode: 'minimal',
200
- headerBackTitleVisible: false,
201
- headerShadowVisible: false
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
- }
198
+ headerShown: false,
199
+ statusBarTranslucent: true,
200
+ statusBarBackgroundColor: 'transparent'
201
+ }
224
202
 
225
203
  return createElement(SafeAreaProvider,
226
204
  null,
@@ -0,0 +1,108 @@
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
+ export function useInnerHeaderHeight (pageconfig) {
7
+ if (pageconfig.navigationStyle === 'custom') {
8
+ return 0
9
+ } else {
10
+ const safeAreaTop = useSafeAreaInsets()?.top || 0
11
+ const headerHeight = safeAreaTop + getTitleHeight()
12
+ return headerHeight
13
+ }
14
+ }
15
+
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({
34
+ header: {
35
+ elevation: 3
36
+ },
37
+ headerContent: {
38
+ flexDirection: 'row',
39
+ alignItems: 'center',
40
+ justifyContent: 'center'
41
+ },
42
+ backButton: {
43
+ position: 'absolute',
44
+ height: '100%',
45
+ width: 40,
46
+ left: 0,
47
+ top: 0,
48
+ alignItems: 'center',
49
+ justifyContent: 'center'
50
+ },
51
+ backButtonImage: {
52
+ width: 22,
53
+ height: 22
54
+ },
55
+ title: {
56
+ fontSize: 17,
57
+ fontWeight: 600
58
+ }
59
+ })
60
+
61
+ export function innerNav ({ props, navigation }) {
62
+ const { pageConfig } = props
63
+ const [innerPageConfig, setPageConfig] = useState(pageConfig || {})
64
+ navigation.setPageConfig = (config) => {
65
+ const newConfig = Object.assign({}, innerPageConfig, config)
66
+ setPageConfig(newConfig)
67
+ }
68
+
69
+ const isCustom = innerPageConfig.navigationStyle === 'custom'
70
+ if (isCustom) return null
71
+ const safeAreaTop = useSafeAreaInsets()?.top || 0
72
+
73
+ // 回退按钮的颜色,根据背景色的亮度来进行调节
74
+ const backButtonColor = useMemo(() => {
75
+ return getColorBrightness(innerPageConfig.navigationBarBackgroundColor) > 128 ? '#000000' : '#ffffff'
76
+ }, [innerPageConfig.navigationBarBackgroundColor])
77
+
78
+ // 假设是栈导航,获取栈的长度
79
+ const stackLength = navigation.getState()?.routes?.length
80
+ // 用于外部注册打开RN容器之前的栈长度
81
+ const beforeStackLength = Mpx.config?.rnConfig?.beforeStackLength || 0
82
+
83
+ // 回退按钮与图标
84
+ const backElement = stackLength + beforeStackLength > 1
85
+ ? createElement(ReactNative.TouchableOpacity, {
86
+ style: [styles.backButton],
87
+ onPress: () => { navigation.goBack() }
88
+ }, createElement(ReactNative.Image, {
89
+ source: { uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAABICAYAAACqT5alAAAA2UlEQVR4nO3bMQrCUBRE0Yla6AYEN2nnBrTL+izcitW3MRDkEUWSvPzJvfCqgMwhZbAppWhNbbIHzB1g9wATERFRVyvpkj1irlpJ5X326D7WHh1hbdFD2CLpLmmftm7kfsEe09aNHFiBrT+wAlt/YAW2/sAKbP2BFdj6Ayuwy+ufz6XPL893krZ//O6iu2n4LT8kndLWTRTo4EC7BDo40C6BDg60S6CDA+0S6OBAuwQ6uNWiD2nrJmoIfU7cNWkR2hbb1UfbY7uuWhGWiIg+a/iHuHmA3QPs3gu4JW9Gan+OJAAAAABJRU5ErkJggg==' },
90
+ style: [styles.backButtonImage, { tintColor: backButtonColor }]
91
+ }))
92
+ : null
93
+
94
+ return createElement(ReactNative.View, {
95
+ style: [styles.header, {
96
+ paddingTop: safeAreaTop,
97
+ backgroundColor: innerPageConfig.navigationBarBackgroundColor || '#000000'
98
+ }]
99
+ },
100
+ createElement(ReactNative.View, {
101
+ style: styles.headerContent,
102
+ height: getTitleHeight()
103
+ }, backElement,
104
+ createElement(ReactNative.Text, {
105
+ style: [styles.title, { color: innerPageConfig.navigationBarTextStyle || 'white' }]
106
+ }, innerPageConfig.navigationBarTitleText?.trim() || ''))
107
+ )
108
+ }
@@ -1,4 +1,4 @@
1
- import { createStackNavigator } from '@react-navigation/stack'
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
- createStackNavigator,
9
+ createNativeStackNavigator,
10
10
  NavigationContainer,
11
11
  useHeaderHeight,
12
12
  StackActions,
@@ -1,4 +1,4 @@
1
- import { createNativeStackNavigator as createStackNavigator } from '@react-navigation/native-stack'
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
- createStackNavigator,
9
+ createNativeStackNavigator,
10
10
  NavigationContainer,
11
11
  useHeaderHeight,
12
12
  StackActions,
@@ -1,4 +1,4 @@
1
- import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, createElement, memo, forwardRef, useImperativeHandle, useContext, Fragment, cloneElement, createContext } from 'react'
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, useHeaderHeight } from '../env/navigationHelper'
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 () {
@@ -445,9 +446,28 @@ 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
- // 临时用来存储安卓底部(iOS没有这个)的高度(虚拟按键等高度)根据第一次进入推算
450
- let bottomVirtualHeight = null
451
471
  export function PageWrapperHOC (WrappedComponent) {
452
472
  return function PageWrapperCom ({ navigation, route, pageConfig = {}, ...props }) {
453
473
  const rootRef = useRef(null)
@@ -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
- usePageStatus(navigation, currentPageId)
468
- useLayoutEffect(() => {
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
- const screenDimensions = ReactNative.Dimensions.get('screen')
488
- if (__mpx_mode__ === 'ios') {
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
- // https://github.com/software-mansion/react-native-reanimated/issues/6639 因存在此问题,iOS在页面上进行定宽来暂时规避
544
- style: __mpx_mode__ === 'ios' && currentPageConfig?.navigationStyle !== 'custom'
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())