Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions packages/core/src/platform/createApp.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Mpx from '../index'
import { createElement, memo, useRef, useEffect } from 'react'
import * as ReactNative from 'react-native'
import { initAppProvides } from './export/inject'
import { NavigationContainer, createStackNavigator, SafeAreaProvider } from './env/navigationHelper'

const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)

Expand All @@ -31,8 +32,6 @@ function filterOptions (options, appData) {

export default function createApp (options) {
const appData = {}

const { NavigationContainer, createStackNavigator, SafeAreaProvider } = global.__navigationHelper
// app选项目前不需要进行转换
const { rawOptions, currentInject } = transferOptions(options, 'app', false)
initAppProvides(rawOptions.provide, rawOptions)
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/platform/env/index.ios.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { isFunction, isNumber, isString } from '@mpxjs/utils'
import { createI18n } from '../builtInMixins/i18nMixin'
import * as navigationHelper from './navigationHelper'

export function init (Mpx) {
global.__mpx = Mpx
Expand All @@ -9,6 +10,7 @@ export function init (Mpx) {
error: [],
rejection: []
}
global.__navigationHelper = navigationHelper
if (global.i18n) {
Mpx.i18n = createI18n(global.i18n)
}
Expand Down
17 changes: 17 additions & 0 deletions packages/core/src/platform/env/navigationHelper.android.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { createStackNavigator } from '@react-navigation/stack'
import { NavigationContainer, StackActions } from '@react-navigation/native'
import PortalHost from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal/portal-host'
import { useHeaderHeight } from '@react-navigation/elements'
import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'
import { GestureHandlerRootView } from 'react-native-gesture-handler'

export {
createStackNavigator,
NavigationContainer,
useHeaderHeight,
StackActions,
GestureHandlerRootView,
PortalHost,
SafeAreaProvider,
useSafeAreaInsets
}
17 changes: 17 additions & 0 deletions packages/core/src/platform/env/navigationHelper.ios.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { createNativeStackNavigator as createStackNavigator } from '@react-navigation/native-stack'
import { NavigationContainer, StackActions } from '@react-navigation/native'
import PortalHost from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-portal/portal-host'
import { useHeaderHeight } from '@react-navigation/elements'
import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'
import { GestureHandlerRootView } from 'react-native-gesture-handler'

export {
createStackNavigator,
NavigationContainer,
useHeaderHeight,
StackActions,
GestureHandlerRootView,
PortalHost,
SafeAreaProvider,
useSafeAreaInsets
}
281 changes: 147 additions & 134 deletions packages/core/src/platform/patch/getDefaultOptions.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@ import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, crea
import * as ReactNative from 'react-native'
import { ReactiveEffect } from '../../observer/effect'
import { watch } from '../../observer/watch'
import { reactive, set, del } from '../../observer/reactive'
import { hasOwn, isFunction, noop, isObject, isArray, getByPath, collectDataset, hump2dash, dash2hump, callWithErrorHandling, wrapMethodsWithErrorHandling } from '@mpxjs/utils'
import { del, reactive, set } from '../../observer/reactive'
import { hasOwn, isFunction, noop, isObject, isArray, getByPath, collectDataset, hump2dash, dash2hump, callWithErrorHandling, wrapMethodsWithErrorHandling, error } from '@mpxjs/utils'
import MpxProxy from '../../core/proxy'
import { BEFOREUPDATE, ONLOAD, UPDATED, ONSHOW, ONHIDE, ONRESIZE, REACTHOOKSEXEC } from '../../core/innerLifecycle'
import mergeOptions from '../../core/mergeOptions'
import { queueJob, hasPendingJob } from '../../observer/scheduler'
import { createSelectorQuery, createIntersectionObserver } from '@mpxjs/api-proxy'
import { IntersectionObserverContext, RouteContext, KeyboardAvoidContext } from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/context'
import MpxKeyboardAvoidingView from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view'
import {
IntersectionObserverContext,
KeyboardAvoidContext,
RouteContext
} from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/context'
import { PortalHost, useSafeAreaInsets, GestureHandlerRootView, useHeaderHeight } from '../env/navigationHelper'

const ProviderContext = createContext(null)
function getSystemInfo () {
Expand Down Expand Up @@ -443,6 +448,141 @@ const checkRelation = (options) => {

// 临时用来存储安卓底部(iOS没有这个)的高度(虚拟按键等高度)根据第一次进入推算
let bottomVirtualHeight = null
export function PageWrapperHOC (WrappedComponent) {
return function PageWrapperCom ({ navigation, route, pageConfig = {}, ...props }) {
const rootRef = useRef(null)
const keyboardAvoidRef = useRef(null)
const intersectionObservers = useRef({})
const currentPageId = useMemo(() => ++pageId, [])
const routeContextValRef = useRef({
navigation,
pageId: currentPageId
})
const currentPageConfig = Object.assign({}, global.__mpxPageConfig, pageConfig)
if (!navigation || !route) {
// 独立组件使用时要求传递navigation
error('Using pageWrapper requires passing navigation and route')
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

传递error对象,以及可以直接return

return null
}
usePageStatus(navigation, currentPageId)
useLayoutEffect(() => {
navigation.setOptions({
title: pageConfig.navigationBarTitleText?.trim() || '',
headerStyle: {
backgroundColor: pageConfig.navigationBarBackgroundColor || '#000000'
},
headerTintColor: pageConfig.navigationBarTextStyle || 'white'
})

// TODO 此部分内容在native-stack可删除,用setOptions设置
if (__mpx_mode__ !== 'ios') {
ReactNative.StatusBar.setBarStyle(pageConfig.barStyle || 'dark-content')
ReactNative.StatusBar.setTranslucent(true) // 控制statusbar是否占位
ReactNative.StatusBar.setBackgroundColor('transparent')
}
}, [])

const headerHeight = useHeaderHeight()
const onLayout = () => {
const screenDimensions = ReactNative.Dimensions.get('screen')
if (__mpx_mode__ === 'ios') {
navigation.layout = {
x: 0,
y: headerHeight,
width: screenDimensions.width,
height: screenDimensions.height - headerHeight
}
} else {
if (bottomVirtualHeight === null) {
rootRef.current?.measureInWindow((x, y, width, height) => {
// 沉浸模式的计算方式
bottomVirtualHeight = screenDimensions.height - height - headerHeight
// 非沉浸模式(translucent=true)计算方式, 现在默认是全用沉浸模式,所以先不算这个
// bottomVirtualHeight = windowDimensions.height - height - headerHeight
navigation.layout = {
x: 0,
y: headerHeight,
width: screenDimensions.width,
height: height
}
})
} else {
navigation.layout = {
x: 0,
y: headerHeight, // 这个y值
width: screenDimensions.width,
// 后续页面的layout是通过第一次路由进入时候推算出来的底部区域来推算出来的
height: screenDimensions.height - bottomVirtualHeight - headerHeight
}
}
}
}
const withKeyboardAvoidingView = (element) => {
return createElement(KeyboardAvoidContext.Provider,
{
value: keyboardAvoidRef
},
createElement(MpxKeyboardAvoidingView,
{
style: {
flex: 1
},
contentContainerStyle: {
flex: 1
}
},
element
)
)
}

navigation.insets = useSafeAreaInsets()

return createElement(GestureHandlerRootView,
{
// https://github.com/software-mansion/react-native-reanimated/issues/6639 因存在此问题,iOS在页面上进行定宽来暂时规避
style: __mpx_mode__ === 'ios' && currentPageConfig?.navigationStyle !== 'custom'
? {
height: ReactNative.Dimensions.get('screen').height - useHeaderHeight()
}
: {
flex: 1
}
},
withKeyboardAvoidingView(
createElement(ReactNative.View,
{
style: {
flex: 1,
backgroundColor: currentPageConfig?.backgroundColor || '#fff'
},
ref: rootRef,
onLayout
},
createElement(RouteContext.Provider,
{
value: routeContextValRef.current
},
createElement(IntersectionObserverContext.Provider,
{
value: intersectionObservers.current
},
createElement(PortalHost,
null,
createElement(WrappedComponent, {
...props,
navigation,
route,
id: currentPageId
})
)
)
)
)
))
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const pageWrapper = (component)=>{
return (props)=>{
createElement(component, {...props, navigation, route,id})
}
}

const page = (props)=>{
return ...
}

const page2 =pageWrapper(page)

export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
rawOptions = mergeOptions(rawOptions, type, false)
const components = Object.assign({}, rawOptions.components, currentInject.getComponents())
Expand Down Expand Up @@ -578,139 +718,12 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
}

if (type === 'page') {
const { PortalHost, useSafeAreaInsets, GestureHandlerRootView, useHeaderHeight } = global.__navigationHelper
const pageConfig = Object.assign({}, global.__mpxPageConfig, currentInject.pageConfig)
const Page = ({ navigation, route }) => {
const currentPageId = useMemo(() => ++pageId, [])
const intersectionObservers = useRef({})
const routeContextValRef = useRef({
pageId: currentPageId,
navigation
return (props) => {
createElement(PageWrapperHOC(defaultOptions), {
pageConfig: currentInject.pageConfig,
...props
})
usePageStatus(navigation, currentPageId)
useLayoutEffect(() => {
navigation.setOptions({
title: pageConfig.navigationBarTitleText?.trim() || '',
headerStyle: {
backgroundColor: pageConfig.navigationBarBackgroundColor || '#000000'
},
headerTintColor: pageConfig.navigationBarTextStyle || 'white'
})

// TODO 此部分内容在native-stack可删除,用setOptions设置
if (__mpx_mode__ !== 'ios') {
ReactNative.StatusBar.setBarStyle(pageConfig.barStyle || 'dark-content')
ReactNative.StatusBar.setTranslucent(true) // 控制statusbar是否占位
ReactNative.StatusBar.setBackgroundColor('transparent')
}
}, [])

const rootRef = useRef(null)
const keyboardAvoidRef = useRef(null)
const headerHeight = useHeaderHeight()
const onLayout = () => {
const screenDimensions = ReactNative.Dimensions.get('screen')
if (__mpx_mode__ === 'ios') {
navigation.layout = {
x: 0,
y: headerHeight,
width: screenDimensions.width,
height: screenDimensions.height - headerHeight
}
} else {
if (bottomVirtualHeight === null) {
rootRef.current?.measureInWindow((x, y, width, height) => {
// 沉浸模式的计算方式
bottomVirtualHeight = screenDimensions.height - height - headerHeight
// 非沉浸模式(translucent=true)计算方式, 现在默认是全用沉浸模式,所以先不算这个
// bottomVirtualHeight = windowDimensions.height - height - headerHeight
navigation.layout = {
x: 0,
y: headerHeight,
width: screenDimensions.width,
height: height
}
})
} else {
navigation.layout = {
x: 0,
y: headerHeight, // 这个y值
width: screenDimensions.width,
// 后续页面的layout是通过第一次路由进入时候推算出来的底部区域来推算出来的
height: screenDimensions.height - bottomVirtualHeight - headerHeight
}
}
}
}
const withKeyboardAvoidingView = (element) => {
return createElement(KeyboardAvoidContext.Provider,
{
value: keyboardAvoidRef
},
createElement(MpxKeyboardAvoidingView,
{
style: {
flex: 1
},
contentContainerStyle: {
flex: 1
}
},
element
)
)
}

navigation.insets = useSafeAreaInsets()

return createElement(GestureHandlerRootView,
{
// https://github.com/software-mansion/react-native-reanimated/issues/6639 因存在此问题,iOS在页面上进行定宽来暂时规避
style: __mpx_mode__ === 'ios' && pageConfig.navigationStyle !== 'custom'
? {
height: ReactNative.Dimensions.get('screen').height - useHeaderHeight()
}
: {
flex: 1
}
},
withKeyboardAvoidingView(
createElement(ReactNative.View,
{
style: {
flex: 1,
backgroundColor: pageConfig.backgroundColor || '#ffffff'
},
ref: rootRef,
// 测试过了 键盘拉起后不会重新触发onLayout
onLayout
},
createElement(RouteContext.Provider,
{
value: routeContextValRef.current
},
createElement(IntersectionObserverContext.Provider,
{
value: intersectionObservers.current
},
createElement(PortalHost,
null,
createElement(defaultOptions,
{
navigation,
route,
id: currentPageId
}
)
)
)
)
)
)
)
// todo custom portal host for active route
}
return Page
}
return defaultOptions
}
6 changes: 6 additions & 0 deletions packages/utils/src/log.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const isDev = process.env.NODE_ENV !== 'production'

export function warn (msg, location, e) {
const condition = global.__mpx?.config.ignoreWarning
if (isDev && !e) {
e = new Error('Mpx runtime warn')
}
let ignore = false
if (typeof condition === 'boolean') {
ignore = condition
Expand All @@ -26,6 +29,9 @@ export function warn (msg, location, e) {

export function error (msg, location, e) {
const errorHandler = global.__mpx?.config.errorHandler
if (isDev && !e) {
e = new Error('Mpx runtime error')
}
if (isFunction(errorHandler)) {
errorHandler(msg, location, e)
} else {
Expand Down
Loading