@mpxjs/core 2.10.3-beta.5 → 2.10.4-beta.1

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.3-beta.5",
3
+ "version": "2.10.4-beta.1",
4
4
  "description": "mpx runtime core",
5
5
  "keywords": [
6
6
  "miniprogram",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "main": "src/index.js",
21
21
  "dependencies": {
22
- "@mpxjs/utils": "^2.10.2",
22
+ "@mpxjs/utils": "^2.10.4",
23
23
  "lodash": "^4.1.1",
24
24
  "miniprogram-api-typings": "^3.10.0"
25
25
  },
@@ -144,7 +144,7 @@ export default function _genVnodeTree (astData, contextScope, options) {
144
144
  node.attrsList.forEach((attr) => {
145
145
  if (attr.name === 'class' || attr.name === 'style') {
146
146
  // class/style 的表达式为数组形式,class/style的计算过程需要放到逻辑层,主要是因为有逻辑匹配的过程去生成 vnodeTree
147
- const helper = attr.name === 'class' ? stringify.stringifyClass : stringify.stringifyStyle
147
+ const helper = attr.name === 'class' ? stringify.c : stringify.s
148
148
  let value = ''
149
149
  if (attr.__exp) {
150
150
  let valueArr = evalExps(attr.__exp)
@@ -1,4 +1,4 @@
1
- import { isReact } from '@mpxjs/utils'
1
+ import { isReact, isWeb } from '@mpxjs/utils'
2
2
  import pageStatusMixin from './pageStatusMixin'
3
3
  import proxyEventMixin from './proxyEventMixin'
4
4
  import renderHelperMixin from './renderHelperMixin'
@@ -27,7 +27,7 @@ export default function getBuiltInMixins ({ type, rawOptions = {} }) {
27
27
  i18nMixin(),
28
28
  relationsMixin(type)
29
29
  ]
30
- } else if (__mpx_mode__ === 'web') {
30
+ } else if (isWeb) {
31
31
  bulitInMixins = [
32
32
  proxyEventMixin(),
33
33
  refsMixin(),
@@ -7,6 +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
11
 
11
12
  const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
12
13
 
@@ -31,8 +32,6 @@ function filterOptions (options, appData) {
31
32
 
32
33
  export default function createApp (options) {
33
34
  const appData = {}
34
-
35
- const { NavigationContainer, createStackNavigator, SafeAreaProvider } = global.__navigationHelper
36
35
  // app选项目前不需要进行转换
37
36
  const { rawOptions, currentInject } = transferOptions(options, 'app', false)
38
37
  initAppProvides(rawOptions.provide, rawOptions)
@@ -1,5 +1,6 @@
1
1
  import { isFunction, isNumber, isString } from '@mpxjs/utils'
2
2
  import { createI18n } from '../builtInMixins/i18nMixin'
3
+ import * as navigationHelper from './navigationHelper'
3
4
 
4
5
  export function init (Mpx) {
5
6
  global.__mpx = Mpx
@@ -9,6 +10,7 @@ export function init (Mpx) {
9
10
  error: [],
10
11
  rejection: []
11
12
  }
13
+ global.__navigationHelper = navigationHelper
12
14
  if (global.i18n) {
13
15
  Mpx.i18n = createI18n(global.i18n)
14
16
  }
@@ -0,0 +1,17 @@
1
+ import { createStackNavigator } from '@react-navigation/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
+ createStackNavigator,
10
+ NavigationContainer,
11
+ useHeaderHeight,
12
+ StackActions,
13
+ GestureHandlerRootView,
14
+ PortalHost,
15
+ SafeAreaProvider,
16
+ useSafeAreaInsets
17
+ }
@@ -0,0 +1,17 @@
1
+ import { createNativeStackNavigator as createStackNavigator } 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
+ createStackNavigator,
10
+ NavigationContainer,
11
+ useHeaderHeight,
12
+ StackActions,
13
+ GestureHandlerRootView,
14
+ PortalHost,
15
+ SafeAreaProvider,
16
+ useSafeAreaInsets
17
+ }
@@ -2,18 +2,21 @@ import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, crea
2
2
  import * as ReactNative from 'react-native'
3
3
  import { ReactiveEffect } from '../../observer/effect'
4
4
  import { watch } from '../../observer/watch'
5
- import { reactive, set, del } from '../../observer/reactive'
6
- import { hasOwn, isFunction, noop, isObject, isArray, getByPath, collectDataset, hump2dash, dash2hump, callWithErrorHandling, wrapMethodsWithErrorHandling } from '@mpxjs/utils'
5
+ import { del, reactive, set } from '../../observer/reactive'
6
+ import { hasOwn, isFunction, noop, isObject, isArray, getByPath, collectDataset, hump2dash, dash2hump, callWithErrorHandling, wrapMethodsWithErrorHandling, error } from '@mpxjs/utils'
7
7
  import MpxProxy from '../../core/proxy'
8
8
  import { BEFOREUPDATE, ONLOAD, UPDATED, ONSHOW, ONHIDE, ONRESIZE, REACTHOOKSEXEC } from '../../core/innerLifecycle'
9
9
  import mergeOptions from '../../core/mergeOptions'
10
10
  import { queueJob, hasPendingJob } from '../../observer/scheduler'
11
11
  import { createSelectorQuery, createIntersectionObserver } from '@mpxjs/api-proxy'
12
- import { IntersectionObserverContext, RouteContext, KeyboardAvoidContext } from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/context'
13
12
  import MpxKeyboardAvoidingView from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view'
13
+ import {
14
+ IntersectionObserverContext,
15
+ KeyboardAvoidContext,
16
+ RouteContext
17
+ } from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/context'
18
+ import { PortalHost, useSafeAreaInsets, GestureHandlerRootView, useHeaderHeight } from '../env/navigationHelper'
14
19
 
15
- const windowDimensions = ReactNative.Dimensions.get('window')
16
- const screenDimensions = ReactNative.Dimensions.get('screen')
17
20
  const ProviderContext = createContext(null)
18
21
  function getSystemInfo () {
19
22
  const windowDimensions = ReactNative.Dimensions.get('window')
@@ -48,7 +51,7 @@ function createEffect (proxy, components) {
48
51
  if (tagName === 'block') return Fragment
49
52
  const appComponents = global.__getAppComponents?.() || {}
50
53
  const generichash = proxy.target.generichash || ''
51
- const genericComponents = global.__mpxGenericsMap?.[generichash] || noop
54
+ const genericComponents = global.__mpxGenericsMap[generichash] || noop
52
55
  return components[tagName] || genericComponents(tagName) || appComponents[tagName] || getByPath(ReactNative, tagName)
53
56
  }
54
57
  const innerCreateElement = (type, ...rest) => {
@@ -445,6 +448,141 @@ const checkRelation = (options) => {
445
448
 
446
449
  // 临时用来存储安卓底部(iOS没有这个)的高度(虚拟按键等高度)根据第一次进入推算
447
450
  let bottomVirtualHeight = null
451
+ export function PageWrapperHOC (WrappedComponent) {
452
+ return function PageWrapperCom ({ navigation, route, pageConfig = {}, ...props }) {
453
+ const rootRef = useRef(null)
454
+ const keyboardAvoidRef = useRef(null)
455
+ const intersectionObservers = useRef({})
456
+ const currentPageId = useMemo(() => ++pageId, [])
457
+ const routeContextValRef = useRef({
458
+ navigation,
459
+ pageId: currentPageId
460
+ })
461
+ const currentPageConfig = Object.assign({}, global.__mpxPageConfig, pageConfig)
462
+ if (!navigation || !route) {
463
+ // 独立组件使用时要求传递navigation
464
+ error('Using pageWrapper requires passing navigation and route')
465
+ return null
466
+ }
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()
486
+ 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
+ }
519
+ }
520
+ const withKeyboardAvoidingView = (element) => {
521
+ return createElement(KeyboardAvoidContext.Provider,
522
+ {
523
+ value: keyboardAvoidRef
524
+ },
525
+ createElement(MpxKeyboardAvoidingView,
526
+ {
527
+ style: {
528
+ flex: 1
529
+ },
530
+ contentContainerStyle: {
531
+ flex: 1
532
+ }
533
+ },
534
+ element
535
+ )
536
+ )
537
+ }
538
+
539
+ navigation.insets = useSafeAreaInsets()
540
+
541
+ return createElement(GestureHandlerRootView,
542
+ {
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
+ }
551
+ },
552
+ withKeyboardAvoidingView(
553
+ createElement(ReactNative.View,
554
+ {
555
+ style: {
556
+ flex: 1,
557
+ backgroundColor: currentPageConfig?.backgroundColor || '#fff'
558
+ },
559
+ ref: rootRef,
560
+ onLayout
561
+ },
562
+ createElement(RouteContext.Provider,
563
+ {
564
+ value: routeContextValRef.current
565
+ },
566
+ createElement(IntersectionObserverContext.Provider,
567
+ {
568
+ value: intersectionObservers.current
569
+ },
570
+ createElement(PortalHost,
571
+ null,
572
+ createElement(WrappedComponent, {
573
+ ...props,
574
+ navigation,
575
+ route,
576
+ id: currentPageId
577
+ })
578
+ )
579
+ )
580
+ )
581
+ )
582
+ ))
583
+ }
584
+ }
585
+
448
586
  export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
449
587
  rawOptions = mergeOptions(rawOptions, type, false)
450
588
  const components = Object.assign({}, rawOptions.components, currentInject.getComponents())
@@ -580,138 +718,11 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
580
718
  }
581
719
 
582
720
  if (type === 'page') {
583
- const { PortalHost, useSafeAreaInsets, GestureHandlerRootView, useHeaderHeight } = global.__navigationHelper
584
- const pageConfig = Object.assign({}, global.__mpxPageConfig, currentInject.pageConfig)
585
- const Page = ({ navigation, route }) => {
586
- const currentPageId = useMemo(() => ++pageId, [])
587
- const intersectionObservers = useRef({})
588
- const routeContextValRef = useRef({
589
- pageId: currentPageId,
590
- navigation
721
+ return (props) =>
722
+ createElement(PageWrapperHOC(defaultOptions), {
723
+ pageConfig: currentInject.pageConfig,
724
+ ...props
591
725
  })
592
- usePageStatus(navigation, currentPageId)
593
- useLayoutEffect(() => {
594
- navigation.setOptions({
595
- title: pageConfig.navigationBarTitleText?.trim() || '',
596
- headerStyle: {
597
- backgroundColor: pageConfig.navigationBarBackgroundColor || '#000000'
598
- },
599
- headerTintColor: pageConfig.navigationBarTextStyle || 'white'
600
- })
601
-
602
- // TODO 此部分内容在native-stack可删除,用setOptions设置
603
- if (__mpx_mode__ === 'android' || __mpx_mode__ === 'harmony') {
604
- ReactNative.StatusBar.setBarStyle(pageConfig.barStyle || 'dark-content')
605
- ReactNative.StatusBar.setTranslucent(true) // 控制statusbar是否占位
606
- ReactNative.StatusBar.setBackgroundColor('transparent')
607
- }
608
- }, [])
609
-
610
- const rootRef = useRef(null)
611
- const keyboardAvoidRef = useRef(null)
612
- const headerHeight = useHeaderHeight()
613
- const onLayout = () => {
614
- if (__mpx_mode__ === 'ios') {
615
- navigation.layout = {
616
- x: 0,
617
- y: headerHeight,
618
- width: windowDimensions.width,
619
- height: screenDimensions.height - headerHeight
620
- }
621
- } else {
622
- if (bottomVirtualHeight === null) {
623
- rootRef.current?.measureInWindow((height) => {
624
- // 沉浸模式的计算方式
625
- bottomVirtualHeight = screenDimensions.height - height - headerHeight
626
- // 非沉浸模式(translucent=true)计算方式, 现在默认是全用沉浸模式,所以先不算这个
627
- // bottomVirtualHeight = windowDimensions.height - height - headerHeight
628
- navigation.layout = {
629
- x: 0,
630
- y: headerHeight,
631
- width: windowDimensions.width,
632
- height: height
633
- }
634
- })
635
- } else {
636
- navigation.layout = {
637
- x: 0,
638
- y: headerHeight, // 这个y值
639
- width: windowDimensions.width,
640
- // 后续页面的layout是通过第一次路由进入时候推算出来的底部区域来推算出来的
641
- height: screenDimensions.height - bottomVirtualHeight - headerHeight
642
- }
643
- }
644
- }
645
- }
646
- const withKeyboardAvoidingView = (element) => {
647
- return createElement(KeyboardAvoidContext.Provider,
648
- {
649
- value: keyboardAvoidRef
650
- },
651
- createElement(MpxKeyboardAvoidingView,
652
- {
653
- style: {
654
- flex: 1
655
- },
656
- contentContainerStyle: {
657
- flex: 1
658
- }
659
- },
660
- element
661
- )
662
- )
663
- }
664
-
665
- navigation.insets = useSafeAreaInsets()
666
-
667
- return createElement(GestureHandlerRootView,
668
- {
669
- // https://github.com/software-mansion/react-native-reanimated/issues/6639 因存在此问题,iOS在页面上进行定宽来暂时规避
670
- style: __mpx_mode__ === 'ios' && pageConfig.navigationStyle !== 'custom'
671
- ? {
672
- height: ReactNative.Dimensions.get('screen').height - useHeaderHeight()
673
- }
674
- : {
675
- flex: 1
676
- }
677
- },
678
- withKeyboardAvoidingView(
679
- createElement(ReactNative.View,
680
- {
681
- style: {
682
- flex: 1,
683
- backgroundColor: pageConfig.backgroundColor || '#ffffff'
684
- },
685
- ref: rootRef,
686
- // 测试过了 键盘拉起后不会重新触发onLayout
687
- onLayout
688
- },
689
- createElement(RouteContext.Provider,
690
- {
691
- value: routeContextValRef.current
692
- },
693
- createElement(IntersectionObserverContext.Provider,
694
- {
695
- value: intersectionObservers.current
696
- },
697
- createElement(PortalHost,
698
- null,
699
- createElement(defaultOptions,
700
- {
701
- navigation,
702
- route,
703
- id: currentPageId
704
- }
705
- )
706
- )
707
- )
708
- )
709
- )
710
- )
711
- )
712
- // todo custom portal host for active route
713
- }
714
- return Page
715
726
  }
716
727
  return defaultOptions
717
728
  }