@mpxjs/core 2.10.3 → 2.10.4

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",
3
+ "version": "2.10.4",
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
  },
@@ -109,5 +109,5 @@
109
109
  "url": "https://github.com/didi/mpx/issues"
110
110
  },
111
111
  "sideEffects": false,
112
- "gitHead": "043c9bc770ce9cc11f865bab67f46849ff573728"
112
+ "gitHead": "c877bcebc894c75fe107f7b997cee5b494932e43"
113
113
  }
@@ -37,7 +37,8 @@ const rulesMap = {
37
37
  wxToDd: extend({}, defaultConvertRule, wxToDdRule),
38
38
  wxToJd: extend({}, defaultConvertRule, wxToJdRule),
39
39
  wxToIos: extend({}, defaultConvertRule, wxToReactRule),
40
- wxToAndroid: extend({}, defaultConvertRule, wxToReactRule)
40
+ wxToAndroid: extend({}, defaultConvertRule, wxToReactRule),
41
+ wxToHarmony: extend({}, defaultConvertRule, wxToReactRule)
41
42
  }
42
43
 
43
44
  export function getConvertRule (convertMode) {
@@ -7,7 +7,8 @@ const convertModes = {
7
7
  'wx-jd': 'wxToJd',
8
8
  'wx-dd': 'wxToDd',
9
9
  'wx-ios': 'wxToIos',
10
- 'wx-android': 'wxToAndroid'
10
+ 'wx-android': 'wxToAndroid',
11
+ 'wx-harmony': 'wxToHarmony'
11
12
  }
12
13
 
13
14
  export function getConvertMode (srcMode) {
@@ -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,3 +1,4 @@
1
+ import { isReact, isWeb } from '@mpxjs/utils'
1
2
  import pageStatusMixin from './pageStatusMixin'
2
3
  import proxyEventMixin from './proxyEventMixin'
3
4
  import renderHelperMixin from './renderHelperMixin'
@@ -17,7 +18,7 @@ import pageIdMixin from './pageIdMixin'
17
18
 
18
19
  export default function getBuiltInMixins ({ type, rawOptions = {} }) {
19
20
  let bulitInMixins
20
- if (__mpx_mode__ === 'ios' || __mpx_mode__ === 'android') {
21
+ if (isReact) {
21
22
  bulitInMixins = [
22
23
  proxyEventMixin(),
23
24
  directiveHelperMixin(),
@@ -26,7 +27,7 @@ export default function getBuiltInMixins ({ type, rawOptions = {} }) {
26
27
  i18nMixin(),
27
28
  relationsMixin(type)
28
29
  ]
29
- } else if (__mpx_mode__ === 'web') {
30
+ } else if (isWeb) {
30
31
  bulitInMixins = [
31
32
  proxyEventMixin(),
32
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,20 +2,25 @@ 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
20
  const ProviderContext = createContext(null)
16
- const windowDimensions = ReactNative.Dimensions.get('window')
17
- const screenDimensions = ReactNative.Dimensions.get('screen')
18
21
  function getSystemInfo () {
22
+ const windowDimensions = ReactNative.Dimensions.get('window')
23
+ const screenDimensions = ReactNative.Dimensions.get('screen')
19
24
  return {
20
25
  deviceOrientation: windowDimensions.width > windowDimensions.height ? 'landscape' : 'portrait',
21
26
  size: {
@@ -443,6 +448,141 @@ const checkRelation = (options) => {
443
448
 
444
449
  // 临时用来存储安卓底部(iOS没有这个)的高度(虚拟按键等高度)根据第一次进入推算
445
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: pageConfig.navigationBarTitleText?.trim() || '',
471
+ headerStyle: {
472
+ backgroundColor: pageConfig.navigationBarBackgroundColor || '#000000'
473
+ },
474
+ headerTintColor: pageConfig.navigationBarTextStyle || 'white'
475
+ })
476
+
477
+ // TODO 此部分内容在native-stack可删除,用setOptions设置
478
+ if (__mpx_mode__ !== 'ios') {
479
+ ReactNative.StatusBar.setBarStyle(pageConfig.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
+
446
586
  export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
447
587
  rawOptions = mergeOptions(rawOptions, type, false)
448
588
  const components = Object.assign({}, rawOptions.components, currentInject.getComponents())
@@ -578,138 +718,11 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
578
718
  }
579
719
 
580
720
  if (type === 'page') {
581
- const { PortalHost, useSafeAreaInsets, GestureHandlerRootView, useHeaderHeight } = global.__navigationHelper
582
- const pageConfig = Object.assign({}, global.__mpxPageConfig, currentInject.pageConfig)
583
- const Page = ({ navigation, route }) => {
584
- const currentPageId = useMemo(() => ++pageId, [])
585
- const intersectionObservers = useRef({})
586
- const routeContextValRef = useRef({
587
- pageId: currentPageId,
588
- navigation
721
+ return (props) =>
722
+ createElement(PageWrapperHOC(defaultOptions), {
723
+ pageConfig: currentInject.pageConfig,
724
+ ...props
589
725
  })
590
- usePageStatus(navigation, currentPageId)
591
- useLayoutEffect(() => {
592
- navigation.setOptions({
593
- title: pageConfig.navigationBarTitleText?.trim() || '',
594
- headerStyle: {
595
- backgroundColor: pageConfig.navigationBarBackgroundColor || '#000000'
596
- },
597
- headerTintColor: pageConfig.navigationBarTextStyle || 'white'
598
- })
599
-
600
- // TODO 此部分内容在native-stack可删除,用setOptions设置
601
- if (__mpx_mode__ === 'android') {
602
- ReactNative.StatusBar.setBarStyle(pageConfig.barStyle || 'dark-content')
603
- ReactNative.StatusBar.setTranslucent(true) // 控制statusbar是否占位
604
- ReactNative.StatusBar.setBackgroundColor('transparent')
605
- }
606
- }, [])
607
-
608
- const rootRef = useRef(null)
609
- const keyboardAvoidRef = useRef(null)
610
- const headerHeight = useHeaderHeight()
611
- const onLayout = () => {
612
- if (__mpx_mode__ === 'ios') {
613
- navigation.layout = {
614
- x: 0,
615
- y: headerHeight,
616
- width: windowDimensions.width,
617
- height: screenDimensions.height - headerHeight
618
- }
619
- } else {
620
- if (bottomVirtualHeight === null) {
621
- rootRef.current?.measureInWindow((height) => {
622
- // 沉浸模式的计算方式
623
- bottomVirtualHeight = screenDimensions.height - height - headerHeight
624
- // 非沉浸模式(translucent=true)计算方式, 现在默认是全用沉浸模式,所以先不算这个
625
- // bottomVirtualHeight = windowDimensions.height - height - headerHeight
626
- navigation.layout = {
627
- x: 0,
628
- y: headerHeight,
629
- width: windowDimensions.width,
630
- height: height
631
- }
632
- })
633
- } else {
634
- navigation.layout = {
635
- x: 0,
636
- y: headerHeight, // 这个y值
637
- width: windowDimensions.width,
638
- // 后续页面的layout是通过第一次路由进入时候推算出来的底部区域来推算出来的
639
- height: screenDimensions.height - bottomVirtualHeight - headerHeight
640
- }
641
- }
642
- }
643
- }
644
- const withKeyboardAvoidingView = (element) => {
645
- return createElement(KeyboardAvoidContext.Provider,
646
- {
647
- value: keyboardAvoidRef
648
- },
649
- createElement(MpxKeyboardAvoidingView,
650
- {
651
- style: {
652
- flex: 1
653
- },
654
- contentContainerStyle: {
655
- flex: 1
656
- }
657
- },
658
- element
659
- )
660
- )
661
- }
662
-
663
- navigation.insets = useSafeAreaInsets()
664
-
665
- return createElement(GestureHandlerRootView,
666
- {
667
- // https://github.com/software-mansion/react-native-reanimated/issues/6639 因存在此问题,iOS在页面上进行定宽来暂时规避
668
- style: __mpx_mode__ === 'ios' && pageConfig.navigationStyle !== 'custom'
669
- ? {
670
- height: ReactNative.Dimensions.get('screen').height - useHeaderHeight()
671
- }
672
- : {
673
- flex: 1
674
- }
675
- },
676
- withKeyboardAvoidingView(
677
- createElement(ReactNative.View,
678
- {
679
- style: {
680
- flex: 1,
681
- backgroundColor: pageConfig.backgroundColor || '#ffffff'
682
- },
683
- ref: rootRef,
684
- // 测试过了 键盘拉起后不会重新触发onLayout
685
- onLayout
686
- },
687
- createElement(RouteContext.Provider,
688
- {
689
- value: routeContextValRef.current
690
- },
691
- createElement(IntersectionObserverContext.Provider,
692
- {
693
- value: intersectionObservers.current
694
- },
695
- createElement(PortalHost,
696
- null,
697
- createElement(defaultOptions,
698
- {
699
- navigation,
700
- route,
701
- id: currentPageId
702
- }
703
- )
704
- )
705
- )
706
- )
707
- )
708
- )
709
- )
710
- // todo custom portal host for active route
711
- }
712
- return Page
713
726
  }
714
727
  return defaultOptions
715
728
  }