@mpxjs/core 2.9.70-alpha.0 → 2.9.71

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.
Files changed (37) hide show
  1. package/@types/global.d.ts +1 -1
  2. package/LICENSE +433 -0
  3. package/package.json +9 -6
  4. package/src/convertor/convertor.js +0 -2
  5. package/src/convertor/getConvertMode.js +0 -1
  6. package/src/core/mergeOptions.js +3 -6
  7. package/src/core/proxy.js +17 -16
  8. package/src/index.js +3 -14
  9. package/src/observer/reactive.js +4 -3
  10. package/src/platform/builtInMixins/directiveHelperMixin.ios.js +4 -1
  11. package/src/platform/builtInMixins/index.js +0 -5
  12. package/src/platform/builtInMixins/proxyEventMixin.web.js +53 -5
  13. package/src/platform/builtInMixins/styleHelperMixin.ios.js +1 -1
  14. package/src/platform/createApp.ios.js +54 -54
  15. package/src/platform/createApp.js +26 -37
  16. package/src/platform/env/event.js +105 -0
  17. package/src/platform/env/index.ios.js +51 -0
  18. package/src/platform/env/index.js +8 -0
  19. package/src/platform/env/index.web.js +48 -0
  20. package/src/{external → platform/env}/vuePlugin.js +10 -4
  21. package/src/platform/export/index.js +1 -1
  22. package/src/platform/export/{apiInject.js → inject.js} +2 -3
  23. package/src/platform/patch/builtInKeysMap.js +1 -1
  24. package/src/platform/patch/getDefaultOptions.ios.js +18 -19
  25. package/src/platform/patch/getDefaultOptions.js +0 -2
  26. package/src/platform/patch/index.js +3 -3
  27. package/src/convertor/wxToTenon.js +0 -86
  28. package/src/external/vue.js +0 -1
  29. package/src/external/vue.tenon.js +0 -13
  30. package/src/external/vue.web.js +0 -6
  31. package/src/platform/builtInMixins/pageStatusMixin.tenon.js +0 -40
  32. package/src/platform/builtInMixins/proxyEventMixin.tenon.js +0 -46
  33. package/src/platform/export/apiInject.tenon.js +0 -1
  34. package/src/platform/export/index.tenon.js +0 -78
  35. package/src/platform/patch/getDefaultOptions.tenon.js +0 -99
  36. package/src/platform/patch/lifecycle/index.tenon.js +0 -52
  37. /package/src/platform/export/{apiInject.web.js → inject.web.js} +0 -0
@@ -34,6 +34,7 @@ export class Observer {
34
34
 
35
35
  constructor (value, shallow) {
36
36
  this.value = value
37
+ this.shallow = shallow
37
38
  def(value, ObKey, this)
38
39
  if (Array.isArray(value)) {
39
40
  const augment = hasProto && arrayProtoAugment
@@ -120,7 +121,7 @@ export function defineReactive (obj, key, val, shallow) {
120
121
  const getter = property && property.get
121
122
  const setter = property && property.set
122
123
 
123
- let childOb = !shallow && observe(val)
124
+ let childOb = shallow ? getObserver(val) : observe(val)
124
125
  Object.defineProperty(obj, key, {
125
126
  enumerable: true,
126
127
  configurable: true,
@@ -149,7 +150,7 @@ export function defineReactive (obj, key, val, shallow) {
149
150
  } else {
150
151
  val = newVal
151
152
  }
152
- childOb = !shallow && observe(newVal)
153
+ childOb = shallow ? getObserver(newVal) : observe(newVal)
153
154
  dep.notify()
154
155
  }
155
156
  })
@@ -175,7 +176,7 @@ export function set (target, key, val) {
175
176
  target[key] = val
176
177
  return val
177
178
  }
178
- defineReactive(ob.value, key, val)
179
+ defineReactive(ob.value, key, val, ob.shallow)
179
180
  ob.dep.notify()
180
181
  return val
181
182
  }
@@ -1,7 +1,10 @@
1
1
  export default function directiveHelperMixin () {
2
2
  return {
3
3
  methods: {
4
- __getWxKey (item, key) {
4
+ __getWxKey (item, key, index) {
5
+ if (key === 'index') {
6
+ return index
7
+ }
5
8
  return key === '*this' ? item : item[key]
6
9
  }
7
10
  }
@@ -37,11 +37,6 @@ export default function getBuiltInMixins ({ type, rawOptions = {} }) {
37
37
  // 由于relation可能是通过mixin注入的,不能通过当前的用户options中是否存在relations来简单判断是否注入该项mixin
38
38
  relationsMixin(type)
39
39
  ]
40
- } else if (__mpx_mode__ === 'tenon') {
41
- bulitInMixins = [
42
- proxyEventMixin(),
43
- pageStatusMixin(type)
44
- ]
45
40
  } else {
46
41
  // 此为差异抹平类mixins,原生模式下也需要注入也抹平平台差异
47
42
  bulitInMixins = [
@@ -1,4 +1,5 @@
1
- import { setByPath } from '@mpxjs/utils'
1
+ import { setByPath, error, parseDataset } from '@mpxjs/utils'
2
+ import Mpx from '../../index'
2
3
 
3
4
  export default function proxyEventMixin () {
4
5
  return {
@@ -19,11 +20,58 @@ export default function proxyEventMixin () {
19
20
  const value = filterMethod ? (innerFilter[filterMethod] ? innerFilter[filterMethod](originValue) : typeof this[filterMethod] === 'function' && this[filterMethod]) : originValue
20
21
  setByPath(this, expr, value)
21
22
  },
22
- __invokeHandler (eventName, $event) {
23
- const handler = this[eventName]
24
- if (handler && typeof handler === 'function') {
25
- handler.call(this, $event)
23
+ __invoke (rawEvent, eventConfig = []) {
24
+ if (typeof Mpx.config.proxyEventHandler === 'function') {
25
+ try {
26
+ Mpx.config.proxyEventHandler(rawEvent)
27
+ } catch (e) {}
26
28
  }
29
+ const location = this.__mpxProxy.options.mpxFileResource
30
+
31
+ if (rawEvent.target && !rawEvent.target._datasetProcessed) {
32
+ const originalDataset = rawEvent.target.dataset
33
+ Object.defineProperty(rawEvent.target, 'dataset', {
34
+ get: () => parseDataset(originalDataset),
35
+ configurable: true,
36
+ enumerable: true
37
+ })
38
+ rawEvent.target._datasetProcessed = true
39
+ }
40
+ if (rawEvent.currentTarget && !rawEvent.currentTarget._datasetProcessed) {
41
+ const originalDataset = rawEvent.currentTarget.dataset
42
+ Object.defineProperty(rawEvent.currentTarget, 'dataset', {
43
+ get: () => parseDataset(originalDataset),
44
+ configurable: true,
45
+ enumerable: true
46
+ })
47
+ rawEvent.currentTarget._datasetProcessed = true
48
+ }
49
+
50
+ let returnedValue
51
+ eventConfig.forEach((item) => {
52
+ const callbackName = item[0]
53
+ if (callbackName) {
54
+ const params =
55
+ item.length > 1
56
+ ? item.slice(1).map((item) => {
57
+ if (item === '__mpx_event__') {
58
+ return rawEvent
59
+ } else {
60
+ return item
61
+ }
62
+ })
63
+ : [rawEvent]
64
+ if (typeof this[callbackName] === 'function') {
65
+ returnedValue = this[callbackName].apply(this, params)
66
+ } else {
67
+ error(
68
+ `Instance property [${callbackName}] is not function, please check.`,
69
+ location
70
+ )
71
+ }
72
+ }
73
+ })
74
+ return returnedValue
27
75
  }
28
76
  }
29
77
  }
@@ -181,7 +181,7 @@ export default function styleHelperMixin () {
181
181
  } else if (appClassMap[className]) {
182
182
  // todo 全局样式在每个页面和组件中生效,以支持全局原子类,后续支持样式模块复用后可考虑移除
183
183
  Object.assign(result, appClassMap[className])
184
- } else if (this.__props[className] && isObject(this.__props[className])) {
184
+ } else if (isObject(this.__props[className])) {
185
185
  // externalClasses必定以对象形式传递下来
186
186
  Object.assign(result, this.__props[className])
187
187
  }
@@ -1,12 +1,12 @@
1
1
  import transferOptions from '../core/transferOptions'
2
2
  import builtInKeysMap from './patch/builtInKeysMap'
3
- import { makeMap, spreadProp, parseUrlQuery, getFocusedNavigation, hasOwn, extend } from '@mpxjs/utils'
3
+ import { makeMap, spreadProp, getFocusedNavigation, hasOwn } from '@mpxjs/utils'
4
4
  import { mergeLifecycle } from '../convertor/mergeLifecycle'
5
5
  import { LIFECYCLE } from '../platform/patch/lifecycle/index'
6
6
  import Mpx from '../index'
7
7
  import { createElement, memo, useRef, useEffect } from 'react'
8
8
  import * as ReactNative from 'react-native'
9
- import { ref } from '../observer/ref'
9
+ import { Image } from 'react-native'
10
10
 
11
11
  const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
12
12
 
@@ -29,22 +29,27 @@ function filterOptions (options, appData) {
29
29
  return newOptions
30
30
  }
31
31
 
32
- function createAppInstance (appData) {
33
- return extend({}, Mpx.prototype, appData)
34
- }
35
-
36
- export default function createApp (option, config = {}) {
32
+ export default function createApp (options) {
37
33
  const appData = {}
38
34
 
39
35
  const { NavigationContainer, createStackNavigator, SafeAreaProvider } = global.__navigationHelper
40
36
  // app选项目前不需要进行转换
41
- const { rawOptions, currentInject } = transferOptions(option, 'app', false)
37
+ const { rawOptions, currentInject } = transferOptions(options, 'app', false)
42
38
  const defaultOptions = filterOptions(spreadProp(rawOptions, 'methods'), appData)
43
- defaultOptions.onAppInit && defaultOptions.onAppInit()
44
39
  // 在页面script执行前填充getApp()
45
40
  global.getApp = function () {
46
41
  return appData
47
42
  }
43
+
44
+ // 模拟小程序appInstance在热启动时不会重新创建的行为,在外部创建跟随js context的appInstance
45
+ const appInstance = Object.assign({}, appData, Mpx.prototype)
46
+
47
+ defaultOptions.onShow && global.__mpxAppCbs.show.push(defaultOptions.onShow.bind(appInstance))
48
+ defaultOptions.onHide && global.__mpxAppCbs.hide.push(defaultOptions.onHide.bind(appInstance))
49
+ defaultOptions.onError && global.__mpxAppCbs.error.push(defaultOptions.onError.bind(appInstance))
50
+ defaultOptions.onUnhandledRejection && global.__mpxAppCbs.rejection.push(defaultOptions.onUnhandledRejection.bind(appInstance))
51
+ defaultOptions.onAppInit && defaultOptions.onAppInit()
52
+
48
53
  const pages = currentInject.getPages() || {}
49
54
  const firstPage = currentInject.firstPage
50
55
  const Stack = createStackNavigator()
@@ -80,63 +85,51 @@ export default function createApp (option, config = {}) {
80
85
  }
81
86
  }
82
87
 
83
- global.__mpxAppCbs = global.__mpxAppCbs || {
84
- show: [],
85
- hide: [],
86
- error: []
87
- }
88
-
89
88
  global.__mpxAppLaunched = false
90
-
91
- global.__mpxAppFocusedState = ref('show')
92
89
  global.__mpxOptionsMap[currentInject.moduleId] = memo((props) => {
93
- const instanceRef = useRef(null)
94
- if (!instanceRef.current) {
95
- instanceRef.current = createAppInstance(appData)
96
- }
97
- const instance = instanceRef.current
90
+ const firstRef = useRef(true)
98
91
  const initialRouteRef = useRef({
99
92
  initialRouteName: firstPage,
100
93
  initialParams: {}
101
94
  })
95
+ if (firstRef.current) {
96
+ // 热启动情况下,app会被销毁重建,将__mpxAppHotLaunched重置保障路由等初始化逻辑正确执行
97
+ global.__mpxAppHotLaunched = false
98
+ // 热启动情况下重置__mpxPagesMap避免页面销毁函数未及时执行时错误地引用到之前的navigation
99
+ global.__mpxPagesMap = {}
100
+ firstRef.current = false
101
+ }
102
+ if (!global.__mpxAppHotLaunched) {
103
+ const { initialRouteName, initialParams } = Mpx.config.rnConfig.parseAppProps?.(props) || {}
104
+ initialRouteRef.current.initialRouteName = initialRouteName || initialRouteRef.current.initialRouteName
105
+ initialRouteRef.current.initialParams = initialParams || initialRouteRef.current.initialParams
102
106
 
103
- if (!global.__mpxAppLaunched) {
104
- const parsed = Mpx.config.rnConfig.parseAppProps?.(props) || {}
105
- if (parsed.url) {
106
- const { path, queryObj } = parseUrlQuery(parsed.url)
107
- Object.assign(initialRouteRef.current, {
108
- initialRouteName: path.startsWith('/') ? path.slice(1) : path,
109
- initialParams: queryObj
110
- })
111
- }
112
107
  global.__mpxAppOnLaunch = (navigation) => {
113
- global.__mpxAppLaunched = true
114
108
  const state = navigation.getState()
115
109
  Mpx.config.rnConfig.onStateChange?.(state)
116
110
  const current = state.routes[state.index]
117
- global.__mpxEnterOptions = {
111
+ const options = {
118
112
  path: current.name,
119
113
  query: current.params,
120
114
  scene: 0,
121
115
  shareTicket: '',
122
- referrerInfo: {}
116
+ referrerInfo: {},
117
+ isLaunch: true
123
118
  }
124
- defaultOptions.onLaunch && defaultOptions.onLaunch.call(instance, global.__mpxEnterOptions)
125
- defaultOptions.onShow && defaultOptions.onShow.call(instance, global.__mpxEnterOptions)
119
+ global.__mpxEnterOptions = options
120
+ if (!global.__mpxAppLaunched) {
121
+ global.__mpxLaunchOptions = options
122
+ defaultOptions.onLaunch && defaultOptions.onLaunch.call(appInstance, options)
123
+ }
124
+ global.__mpxAppCbs.show.forEach((cb) => {
125
+ cb(options)
126
+ })
127
+ global.__mpxAppLaunched = true
128
+ global.__mpxAppHotLaunched = true
126
129
  }
127
130
  }
128
131
 
129
132
  useEffect(() => {
130
- if (defaultOptions.onShow) {
131
- global.__mpxAppCbs.show.push(defaultOptions.onShow.bind(instance))
132
- }
133
- if (defaultOptions.onHide) {
134
- global.__mpxAppCbs.hide.push(defaultOptions.onHide.bind(instance))
135
- }
136
- if (defaultOptions.onError) {
137
- global.__mpxAppCbs.error.push(defaultOptions.onError.bind(instance))
138
- }
139
-
140
133
  const changeSubscription = ReactNative.AppState.addEventListener('change', (currentState) => {
141
134
  if (currentState === 'active') {
142
135
  let options = global.__mpxEnterOptions
@@ -158,7 +151,7 @@ export default function createApp (option, config = {}) {
158
151
  if (navigation && hasOwn(global.__mpxPageStatusMap, navigation.pageId)) {
159
152
  global.__mpxPageStatusMap[navigation.pageId] = 'show'
160
153
  }
161
- } else if (currentState === 'inactive') {
154
+ } else if (currentState === 'inactive' || currentState === 'background') {
162
155
  global.__mpxAppCbs.hide.forEach((cb) => {
163
156
  cb()
164
157
  })
@@ -187,6 +180,19 @@ export default function createApp (option, config = {}) {
187
180
  }, [])
188
181
 
189
182
  const { initialRouteName, initialParams } = initialRouteRef.current
183
+ const headerBackImageProps = Mpx.config.rnConfig.headerBackImageProps || null
184
+ const navScreenOpts = {
185
+ // 7.x替换headerBackTitleVisible
186
+ // headerBackButtonDisplayMode: 'minimal',
187
+ headerBackTitleVisible: false,
188
+ // 安卓上会出现初始化时闪现导航条的问题
189
+ headerShown: false
190
+ }
191
+ if (headerBackImageProps) {
192
+ navScreenOpts.headerBackImage = () => {
193
+ return createElement(Image, headerBackImageProps)
194
+ }
195
+ }
190
196
  return createElement(SafeAreaProvider,
191
197
  null,
192
198
  createElement(NavigationContainer,
@@ -197,13 +203,7 @@ export default function createApp (option, config = {}) {
197
203
  createElement(Stack.Navigator,
198
204
  {
199
205
  initialRouteName,
200
- screenOptions: {
201
- gestureEnabled: true,
202
- // 7.x替换headerBackTitleVisible
203
- // headerBackButtonDisplayMode: 'minimal',
204
- headerBackTitleVisible: false,
205
- headerMode: 'float'
206
- }
206
+ screenOptions: navScreenOpts
207
207
  },
208
208
  ...getPageScreens(initialRouteName, initialParams)
209
209
  )
@@ -5,7 +5,7 @@ import { makeMap, spreadProp, isBrowser } from '@mpxjs/utils'
5
5
  import { mergeLifecycle } from '../convertor/mergeLifecycle'
6
6
  import { LIFECYCLE } from '../platform/patch/lifecycle/index'
7
7
  import Mpx from '../index'
8
- import { initAppProvides } from './export/apiInject'
8
+ import { initAppProvides } from './export/inject'
9
9
 
10
10
  const appHooksMap = makeMap(mergeLifecycle(LIFECYCLE).app)
11
11
 
@@ -24,19 +24,29 @@ function filterOptions (options, appData) {
24
24
  return newOptions
25
25
  }
26
26
 
27
- export default function createApp (option, config = {}) {
28
- // 在App中挂载mpx对象供周边工具访问,如e2e测试
27
+ export default function createApp (options, config = {}) {
28
+ const appData = {}
29
+ // app选项目前不需要进行转换
30
+ const { rawOptions, currentInject } = transferOptions(options, 'app', false)
29
31
  const builtInMixins = [{
32
+ // 在App中挂载mpx对象供周边工具访问,如e2e测试
30
33
  getMpx () {
31
34
  return Mpx
32
35
  }
33
36
  }]
34
- const appData = {}
35
37
  if (__mpx_mode__ === 'web') {
36
38
  builtInMixins.push({
39
+ beforeCreate () {
40
+ // for vue provide vm access
41
+ Object.assign(this, appData, Mpx.prototype)
42
+ if (isBrowser) {
43
+ rawOptions.onShow && global.__mpxAppCbs.show.push(rawOptions.onShow.bind(this))
44
+ rawOptions.onHide && global.__mpxAppCbs.hide.push(rawOptions.onHide.bind(this))
45
+ rawOptions.onError && global.__mpxAppCbs.error.push(rawOptions.onError.bind(this))
46
+ rawOptions.onUnhandledRejection && global.__mpxAppCbs.rejection.push(rawOptions.onUnhandledRejection.bind(this))
47
+ }
48
+ },
37
49
  created () {
38
- Object.assign(this, Mpx.prototype)
39
- Object.assign(this, appData)
40
50
  const current = this.$root.$options?.router?.currentRoute || {}
41
51
  const options = {
42
52
  path: current.path && current.path.replace(/^\//, ''),
@@ -45,57 +55,36 @@ export default function createApp (option, config = {}) {
45
55
  shareTicket: '',
46
56
  referrerInfo: {}
47
57
  }
58
+ // web不分冷启动和热启动
48
59
  global.__mpxEnterOptions = options
49
- this.$options.onLaunch && this.$options.onLaunch.call(this, options)
50
- global.__mpxAppCbs = global.__mpxAppCbs || {
51
- show: [],
52
- hide: [],
53
- error: []
54
- }
55
- if (isBrowser) {
56
- if (this.$options.onShow) {
57
- this.$options.onShow.call(this, options)
58
- global.__mpxAppCbs.show.push(this.$options.onShow.bind(this))
59
- }
60
- if (this.$options.onHide) {
61
- global.__mpxAppCbs.hide.push(this.$options.onHide.bind(this))
62
- }
63
- if (this.$options.onError) {
64
- global.__mpxAppCbs.error.push(this.$options.onError.bind(this))
65
- }
66
- }
67
- }
68
- })
69
- } else if (__mpx_mode__ === 'tenon') {
70
- // todo add tenon mixins
71
- builtInMixins.push({
72
- onLaunch () {
73
- // console.log('tenon mixins')
60
+ global.__mpxLaunchOptions = options
61
+ rawOptions.onLaunch && rawOptions.onLaunch.call(this, options)
62
+ global.__mpxAppCbs.show.forEach((cb) => {
63
+ cb(options)
64
+ })
74
65
  }
75
66
  })
76
67
  } else {
77
68
  builtInMixins.push({
78
69
  onLaunch () {
79
70
  Object.assign(this, Mpx.prototype)
71
+ initAppProvides(rawOptions.provide, this)
80
72
  }
81
73
  })
82
74
  }
83
- // app选项目前不需要进行转换
84
- const { rawOptions, currentInject } = transferOptions(option, 'app', false)
85
75
  rawOptions.mixins = builtInMixins
86
76
  const defaultOptions = filterOptions(spreadProp(mergeOptions(rawOptions, 'app', false), 'methods'), appData)
87
77
 
88
- if (__mpx_mode__ === 'web' || __mpx_mode__ === 'tenon') {
89
- global.__mpxOptionsMap = global.__mpxOptionsMap || {}
90
- global.__mpxOptionsMap[currentInject.moduleId] = defaultOptions
78
+ if (__mpx_mode__ === 'web') {
91
79
  global.getApp = function () {
92
80
  if (!isBrowser) {
93
81
  console.error('[Mpx runtime error]: Dangerous API! global.getApp method is running in non browser environments')
94
82
  }
95
83
  return appData
96
84
  }
85
+ global.__mpxOptionsMap = global.__mpxOptionsMap || {}
86
+ global.__mpxOptionsMap[currentInject.moduleId] = defaultOptions
97
87
  } else {
98
- initAppProvides(rawOptions)
99
88
  defaultOptions.onAppInit && defaultOptions.onAppInit()
100
89
  const ctor = config.customCtor || global.currentCtor || App
101
90
  ctor(defaultOptions)
@@ -0,0 +1,105 @@
1
+ import { isBrowser } from '@mpxjs/utils'
2
+
3
+ function extendEvent (e, extendObj = {}) {
4
+ Object.keys(extendObj).forEach((key) => {
5
+ Object.defineProperty(e, key, {
6
+ value: extendObj[key],
7
+ enumerable: true,
8
+ configurable: true,
9
+ writable: true
10
+ })
11
+ })
12
+ }
13
+
14
+ function createMpxEvent (layer) {
15
+ let startTimer = null
16
+ let needTap = true
17
+ let touchStartX = 0
18
+ let touchStartY = 0
19
+ let targetElement = null
20
+ const isTouchDevice = document && 'ontouchstart' in document.documentElement
21
+
22
+ const onTouchStart = (event) => {
23
+ if (event.targetTouches?.length > 1) {
24
+ return true
25
+ }
26
+ const touches = event.targetTouches
27
+ targetElement = event.target
28
+ needTap = true
29
+ startTimer = null
30
+ touchStartX = touches[0].pageX
31
+ touchStartY = touches[0].pageY
32
+ startTimer = setTimeout(() => {
33
+ needTap = false
34
+ sendEvent(targetElement, 'longpress', event)
35
+ sendEvent(targetElement, 'longtap', event)
36
+ }, 350)
37
+ }
38
+
39
+ const onTouchMove = (event) => {
40
+ const touch = event.changedTouches[0]
41
+ if (
42
+ Math.abs(touch.pageX - touchStartX) > 1 ||
43
+ Math.abs(touch.pageY - touchStartY) > 1
44
+ ) {
45
+ needTap = false
46
+ startTimer && clearTimeout(startTimer)
47
+ startTimer = null
48
+ }
49
+ }
50
+
51
+ const onTouchEnd = (event) => {
52
+ if (event.targetTouches?.length > 1) {
53
+ return true
54
+ }
55
+ startTimer && clearTimeout(startTimer)
56
+ startTimer = null
57
+ if (needTap) {
58
+ sendEvent(targetElement, 'tap', event)
59
+ }
60
+ }
61
+
62
+ const onClick = (event) => {
63
+ targetElement = event.target
64
+ sendEvent(targetElement, 'tap', event)
65
+ }
66
+
67
+ const sendEvent = (targetElement, type, event) => {
68
+ const touchEvent = new CustomEvent(type, {
69
+ bubbles: true,
70
+ cancelable: true
71
+ })
72
+ const changedTouches = event.changedTouches || []
73
+ extendEvent(touchEvent, {
74
+ timeStamp: event.timeStamp,
75
+ changedTouches,
76
+ touches: changedTouches,
77
+ detail: {
78
+ x: changedTouches[0]?.pageX || event.pageX || 0,
79
+ y: changedTouches[0]?.pageY || event.pageY || 0
80
+ }
81
+ })
82
+ targetElement && targetElement.dispatchEvent(touchEvent)
83
+ }
84
+
85
+ if (isTouchDevice) {
86
+ layer.addEventListener('touchstart', onTouchStart, true)
87
+ layer.addEventListener('touchmove', onTouchMove, true)
88
+ layer.addEventListener('touchend', onTouchEnd, true)
89
+ } else {
90
+ layer.addEventListener('click', onClick, true)
91
+ }
92
+ }
93
+
94
+ export function initEvent () {
95
+ if (isBrowser && !global.__mpxCreatedEvent) {
96
+ global.__mpxCreatedEvent = true
97
+ if (document.readyState === 'complete' || document.readyState === 'interactive') {
98
+ createMpxEvent(document.body)
99
+ } else {
100
+ document.addEventListener('DOMContentLoaded', function () {
101
+ createMpxEvent(document.body)
102
+ }, false)
103
+ }
104
+ }
105
+ }
@@ -0,0 +1,51 @@
1
+ import { createI18n } from '../builtInMixins/i18nMixin'
2
+
3
+ export function init (Mpx) {
4
+ global.__mpx = Mpx
5
+ global.__mpxAppCbs = global.__mpxAppCbs || {
6
+ show: [],
7
+ hide: [],
8
+ error: [],
9
+ rejection: []
10
+ }
11
+ if (global.i18n) {
12
+ Mpx.i18n = createI18n(global.i18n)
13
+ }
14
+ initGlobalErrorHandling()
15
+ }
16
+
17
+ function initGlobalErrorHandling () {
18
+ if (global.ErrorUtils) {
19
+ const defaultHandler = global.ErrorUtils.getGlobalHandler()
20
+ global.ErrorUtils.setGlobalHandler((error, isFatal) => {
21
+ if (global.__mpxAppCbs && global.__mpxAppCbs.error && global.__mpxAppCbs.error.length) {
22
+ global.__mpxAppCbs.error.forEach((cb) => {
23
+ cb(error)
24
+ })
25
+ } else if (defaultHandler) {
26
+ defaultHandler(error, isFatal)
27
+ } else {
28
+ console.error(`${error.name}: ${error.message}\n`)
29
+ }
30
+ })
31
+ }
32
+
33
+ const rejectionTrackingOptions = {
34
+ allRejections: true,
35
+ onUnhandled (id, error) {
36
+ if (global.__mpxAppCbs && global.__mpxAppCbs.rejection && global.__mpxAppCbs.rejection.length) {
37
+ global.__mpxAppCbs.rejection.forEach((cb) => {
38
+ cb(error, id)
39
+ })
40
+ } else {
41
+ console.warn(`UNHANDLED PROMISE REJECTION (id: ${id}): ${error}\n`)
42
+ }
43
+ }
44
+ }
45
+
46
+ if (global?.HermesInternal?.hasPromise?.()) {
47
+ global.HermesInternal?.enablePromiseRejectionTracker?.(rejectionTrackingOptions)
48
+ } else {
49
+ require('promise/setimmediate/rejection-tracking').enable(rejectionTrackingOptions)
50
+ }
51
+ }
@@ -0,0 +1,8 @@
1
+ import { createI18n } from '../builtInMixins/i18nMixin'
2
+
3
+ export function init (Mpx) {
4
+ global.__mpx = Mpx
5
+ if (global.i18n) {
6
+ Mpx.i18n = createI18n(global.i18n)
7
+ }
8
+ }
@@ -0,0 +1,48 @@
1
+ import Vue from 'vue'
2
+ import install from './vuePlugin'
3
+ import { isBrowser, error, warn } from '@mpxjs/utils'
4
+ import { initEvent } from './event'
5
+
6
+ export function init (Mpx) {
7
+ global.__mpx = Mpx
8
+ global.__mpxAppCbs = global.__mpxAppCbs || {
9
+ show: [],
10
+ hide: [],
11
+ error: [],
12
+ rejection: []
13
+ }
14
+ Mpx.__vue = Vue
15
+ Vue.use(install)
16
+ initEvent()
17
+ initGlobalErrorHandling()
18
+ }
19
+
20
+ function initGlobalErrorHandling () {
21
+ Vue.config.errorHandler = (e, vm, info) => {
22
+ error(`Unhandled error occurs${info ? ` during execution of [${info}]` : ''}!`, vm?.__mpxProxy?.options.mpxFileResource, e)
23
+ }
24
+ Vue.config.warnHandler = (msg, vm, trace) => {
25
+ warn(msg, vm?.__mpxProxy?.options.mpxFileResource, trace)
26
+ }
27
+
28
+ if (isBrowser) {
29
+ window.addEventListener('error', (event) => {
30
+ if (global.__mpxAppCbs && global.__mpxAppCbs.error && global.__mpxAppCbs.error.length) {
31
+ global.__mpxAppCbs.error.forEach((cb) => {
32
+ cb(event.error)
33
+ })
34
+ } else {
35
+ console.error(`${event.type}: ${event.message}\n`)
36
+ }
37
+ })
38
+ window.addEventListener('unhandledrejection', (event) => {
39
+ if (global.__mpxAppCbs && global.__mpxAppCbs.rejection && global.__mpxAppCbs.rejection.length) {
40
+ global.__mpxAppCbs.rejection.forEach((cb) => {
41
+ cb(event.reason, event.promise)
42
+ })
43
+ } else {
44
+ console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}\n`)
45
+ }
46
+ })
47
+ }
48
+ }
@@ -1,7 +1,7 @@
1
1
  import { walkChildren, parseSelector, error, hasOwn, collectDataset } from '@mpxjs/utils'
2
2
  import { createSelectorQuery, createIntersectionObserver } from '@mpxjs/api-proxy'
3
3
  import { EffectScope } from 'vue'
4
- import { PausedState } from '../helper/const'
4
+ import { PausedState } from '../../helper/const'
5
5
 
6
6
  const hackEffectScope = () => {
7
7
  EffectScope.prototype.pause = function () {
@@ -60,17 +60,23 @@ export default function install (Vue) {
60
60
  data: {
61
61
  get () {
62
62
  return Object.assign({}, this.$props, this.$data)
63
- }
63
+ },
64
+ enumerable: true,
65
+ configurable: true
64
66
  },
65
67
  dataset: {
66
68
  get () {
67
69
  return collectDataset(this.$attrs, true)
68
- }
70
+ },
71
+ enumerable: true,
72
+ configurable: true
69
73
  },
70
74
  id: {
71
75
  get () {
72
76
  return this.$attrs.id || ''
73
- }
77
+ },
78
+ enumerable: true,
79
+ configurable: true
74
80
  }
75
81
  })
76
82