@mpxjs/core 2.9.66 → 2.9.69-beta.0

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 (52) hide show
  1. package/@types/global.d.ts +2 -0
  2. package/@types/index.d.ts +18 -2
  3. package/package.json +19 -7
  4. package/src/convertor/convertor.js +11 -32
  5. package/src/convertor/wxToAli.js +3 -3
  6. package/src/convertor/wxToReact.js +1 -1
  7. package/src/convertor/wxToSwan.js +3 -3
  8. package/src/convertor/wxToWeb.js +3 -3
  9. package/src/core/mergeOptions.js +1 -1
  10. package/src/core/proxy.js +86 -12
  11. package/src/dynamic/dynamicRenderMixin.js +2 -2
  12. package/src/index.js +3 -14
  13. package/src/observer/reactive.js +5 -4
  14. package/src/observer/ref.js +3 -2
  15. package/src/observer/scheduler.js +4 -0
  16. package/src/observer/watch.js +5 -4
  17. package/src/platform/builtInMixins/directiveHelperMixin.ios.js +4 -1
  18. package/src/platform/builtInMixins/styleHelperMixin.ios.js +28 -25
  19. package/src/platform/createApp.ios.js +110 -42
  20. package/src/platform/createApp.js +8 -8
  21. package/src/platform/env/event.js +108 -0
  22. package/src/platform/env/index.ios.js +51 -0
  23. package/src/platform/env/index.js +8 -0
  24. package/src/platform/env/index.web.js +48 -0
  25. package/src/{external → platform/env}/vuePlugin.js +1 -1
  26. package/src/platform/export/index.js +5 -0
  27. package/src/platform/export/index.web.js +3 -1
  28. package/src/platform/export/inject.js +68 -0
  29. package/src/platform/export/inject.web.js +1 -0
  30. package/src/platform/patch/builtInKeysMap.js +2 -0
  31. package/src/platform/patch/{ali/getDefaultOptions.js → getDefaultOptions.ali.js} +19 -6
  32. package/src/platform/patch/{react/getDefaultOptions.ios.js → getDefaultOptions.ios.js} +286 -200
  33. package/src/platform/patch/{wx/getDefaultOptions.js → getDefaultOptions.js} +20 -11
  34. package/src/platform/patch/{web/getDefaultOptions.js → getDefaultOptions.web.js} +9 -7
  35. package/src/platform/patch/index.js +4 -21
  36. package/src/platform/patch/{ali/lifecycle.js → lifecycle/index.ali.js} +2 -0
  37. package/src/platform/patch/lifecycle/index.js +1 -0
  38. package/src/platform/patch/{swan/lifecycle.js → lifecycle/index.swan.js} +2 -0
  39. package/src/platform/patch/{web/lifecycle.js → lifecycle/index.web.js} +4 -0
  40. package/src/platform/patch/{wx/lifecycle.js → lifecycle/index.wx.js} +2 -0
  41. package/src/runtime/createFactory.js +3 -0
  42. package/LICENSE +0 -433
  43. package/src/external/vue.js +0 -1
  44. package/src/external/vue.web.js +0 -6
  45. package/src/platform/builtInMixins/directiveHelperMixin.android.js +0 -2
  46. package/src/platform/builtInMixins/proxyEventMixin.android.js +0 -2
  47. package/src/platform/builtInMixins/refsMixin.android.js +0 -2
  48. package/src/platform/builtInMixins/styleHelperMixin.android.js +0 -2
  49. package/src/platform/createApp.android.js +0 -2
  50. package/src/platform/patch/react/getDefaultOptions.android.js +0 -1
  51. package/src/platform/patch/react/getDefaultOptions.js +0 -1
  52. package/src/platform/patch/swan/getDefaultOptions.js +0 -34
@@ -1,15 +1,15 @@
1
- import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, useCallback, createElement, memo, forwardRef, useImperativeHandle, useContext, createContext, Fragment, cloneElement } from 'react'
1
+ import { useEffect, useLayoutEffect, useSyncExternalStore, useRef, useMemo, useState, useCallback, createElement, memo, forwardRef, useImperativeHandle, useContext, Fragment, cloneElement } from 'react'
2
2
  import * as ReactNative from 'react-native'
3
- import { ReactiveEffect } from '../../../observer/effect'
4
- import { watch } from '../../../observer/watch'
5
- import { reactive, set, del } from '../../../observer/reactive'
6
- import { hasOwn, isFunction, noop, isObject, getByPath, collectDataset, hump2dash } from '@mpxjs/utils'
7
- import MpxProxy from '../../../core/proxy'
8
- import { BEFOREUPDATE, ONLOAD, UPDATED, ONSHOW, ONHIDE, ONRESIZE, REACTHOOKSEXEC } from '../../../core/innerLifecycle'
9
- import mergeOptions from '../../../core/mergeOptions'
10
- import { queueJob } from '../../../observer/scheduler'
3
+ import { ReactiveEffect } from '../../observer/effect'
4
+ import { watch } from '../../observer/watch'
5
+ import { reactive, set, del } from '../../observer/reactive'
6
+ import { hasOwn, isFunction, noop, isObject, isArray, getByPath, collectDataset, hump2dash, callWithErrorHandling, wrapMethodsWithErrorHandling } from '@mpxjs/utils'
7
+ import MpxProxy from '../../core/proxy'
8
+ import { BEFOREUPDATE, ONLOAD, UPDATED, ONSHOW, ONHIDE, ONRESIZE, REACTHOOKSEXEC } from '../../core/innerLifecycle'
9
+ import mergeOptions from '../../core/mergeOptions'
10
+ import { queueJob, hasPendingJob } from '../../observer/scheduler'
11
11
  import { createSelectorQuery, createIntersectionObserver } from '@mpxjs/api-proxy'
12
- import { IntersectionObserverContext } from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/context'
12
+ import { IntersectionObserverContext, RouteContext, KeyboardAvoidContext } from '@mpxjs/webpack-plugin/lib/runtime/components/react/dist/context'
13
13
 
14
14
  function getSystemInfo () {
15
15
  const window = ReactNative.Dimensions.get('window')
@@ -27,15 +27,14 @@ function getSystemInfo () {
27
27
 
28
28
  function createEffect (proxy, components) {
29
29
  const update = proxy.update = () => {
30
- // pre render for props update
31
- if (proxy.propsUpdatedFlag) {
32
- proxy.updatePreRender()
33
- }
30
+ // react update props in child render(async), do not need exec pre render
31
+ // if (proxy.propsUpdatedFlag) {
32
+ // proxy.updatePreRender()
33
+ // }
34
34
  if (proxy.isMounted()) {
35
35
  proxy.callHook(BEFOREUPDATE)
36
36
  proxy.pendingUpdatedFlag = true
37
37
  }
38
- // eslint-disable-next-line symbol-description
39
38
  proxy.stateVersion = Symbol()
40
39
  proxy.onStoreChange && proxy.onStoreChange()
41
40
  }
@@ -49,11 +48,14 @@ function createEffect (proxy, components) {
49
48
  if (!type) return null
50
49
  return createElement(type, ...rest)
51
50
  }
51
+
52
52
  proxy.effect = new ReactiveEffect(() => {
53
53
  // reset instance
54
54
  proxy.target.__resetInstance()
55
- return proxy.target.__injectedRender(innerCreateElement, getComponent)
55
+ return callWithErrorHandling(proxy.target.__injectedRender.bind(proxy.target), proxy, 'render function', [innerCreateElement, getComponent])
56
56
  }, () => queueJob(update), proxy.scope)
57
+ // render effect允许自触发
58
+ proxy.toggleRecurse(true)
57
59
  }
58
60
 
59
61
  function getRootProps (props) {
@@ -69,126 +71,132 @@ function getRootProps (props) {
69
71
  return rootProps
70
72
  }
71
73
 
72
- function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx }) {
73
- const instance = Object.create({
74
- setData (data, callback) {
75
- return this.__mpxProxy.forceUpdate(data, { sync: true }, callback)
76
- },
77
- getPageId () {
78
- return pageId
79
- },
80
- __getProps () {
81
- const props = propsRef.current
82
- const propsData = {}
83
- Object.keys(validProps).forEach((key) => {
84
- if (hasOwn(props, key)) {
85
- propsData[key] = props[key]
74
+ const instanceProto = {
75
+ setData (data, callback) {
76
+ return this.__mpxProxy.forceUpdate(data, { sync: true }, callback)
77
+ },
78
+ triggerEvent (eventName, eventDetail) {
79
+ const props = this.__props
80
+ const handler = props && (props['bind' + eventName] || props['catch' + eventName] || props['capture-bind' + eventName] || props['capture-catch' + eventName])
81
+ if (handler && typeof handler === 'function') {
82
+ const timeStamp = +new Date()
83
+ const dataset = collectDataset(props)
84
+ const id = props.id || ''
85
+ const eventObj = {
86
+ type: eventName,
87
+ timeStamp,
88
+ target: {
89
+ id,
90
+ dataset,
91
+ targetDataset: dataset
92
+ },
93
+ currentTarget: {
94
+ id,
95
+ dataset
96
+ },
97
+ detail: eventDetail
98
+ }
99
+ handler.call(this, eventObj)
100
+ }
101
+ },
102
+ getPageId () {
103
+ return this.__pageId
104
+ },
105
+ selectComponent (selector) {
106
+ return this.__selectRef(selector, 'component')
107
+ },
108
+ selectAllComponents (selector) {
109
+ return this.__selectRef(selector, 'component', true)
110
+ },
111
+ createSelectorQuery () {
112
+ return createSelectorQuery().in(this)
113
+ },
114
+ createIntersectionObserver (opt) {
115
+ return createIntersectionObserver(this, opt, this.__intersectionCtx)
116
+ },
117
+ __resetInstance () {
118
+ this.__refs = {}
119
+ this.__dispatchedSlotSet = new WeakSet()
120
+ },
121
+ __iter (val, fn) {
122
+ let i, l, keys, key
123
+ const result = []
124
+ if (isArray(val) || typeof val === 'string') {
125
+ for (i = 0, l = val.length; i < l; i++) {
126
+ result.push(fn.call(this, val[i], i))
127
+ }
128
+ } else if (typeof val === 'number') {
129
+ for (i = 0; i < val; i++) {
130
+ result.push(fn.call(this, i + 1, i))
131
+ }
132
+ } else if (isObject(val)) {
133
+ keys = Object.keys(val)
134
+ for (i = 0, l = keys.length; i < l; i++) {
135
+ key = keys[i]
136
+ result.push(fn.call(this, val[key], key, i))
137
+ }
138
+ }
139
+ return result
140
+ },
141
+ __getProps () {
142
+ const props = this.__props
143
+ const validProps = this.__validProps
144
+ const propsData = {}
145
+ Object.keys(validProps).forEach((key) => {
146
+ if (hasOwn(props, key)) {
147
+ propsData[key] = props[key]
148
+ } else {
149
+ const altKey = hump2dash(key)
150
+ if (hasOwn(props, altKey)) {
151
+ propsData[key] = props[altKey]
86
152
  } else {
87
- const altKey = hump2dash(key)
88
- if (hasOwn(props, altKey)) {
89
- propsData[key] = props[altKey]
90
- } else {
91
- let field = validProps[key]
92
- if (isFunction(field) || field === null) {
93
- field = {
94
- type: field
95
- }
153
+ let field = validProps[key]
154
+ if (isFunction(field) || field === null) {
155
+ field = {
156
+ type: field
96
157
  }
97
- // 处理props默认值
98
- propsData[key] = field.value
99
158
  }
159
+ // 处理props默认值
160
+ propsData[key] = field.value
100
161
  }
101
- })
102
- return propsData
103
- },
104
- __resetInstance () {
105
- this.__refs = {}
106
- this.__dispatchedSlotSet = new WeakSet()
107
- },
108
- __getSlot (name) {
109
- const { children } = propsRef.current
110
- if (children) {
111
- const result = []
112
- if (Array.isArray(children)) {
113
- children.forEach(child => {
114
- if (child?.props?.slot === name) {
115
- result.push(child)
116
- }
117
- })
118
- } else {
119
- if (children?.props?.slot === name) {
120
- result.push(children)
162
+ }
163
+ })
164
+ return propsData
165
+ },
166
+ __getSlot (name, slot) {
167
+ const { children } = this.__props
168
+ if (children) {
169
+ let result = []
170
+ if (isArray(children) && !hasOwn(children, '__slot')) {
171
+ children.forEach(child => {
172
+ if (hasOwn(child, '__slot')) {
173
+ if (child.__slot === name) result.push(...child)
174
+ } else if (child?.props?.slot === name) {
175
+ result.push(child)
121
176
  }
122
- }
123
- return result.filter(item => {
124
- if (!isObject(item) || this.__dispatchedSlotSet.has(item)) return false
125
- this.__dispatchedSlotSet.add(item)
126
- return true
127
177
  })
128
- }
129
- return null
130
- },
131
- __injectedRender: currentInject.render || noop,
132
- __getRefsData: currentInject.getRefsData || noop,
133
- // render helper
134
- _i (val, fn) {
135
- let i, l, keys, key
136
- const result = []
137
- if (Array.isArray(val) || typeof val === 'string') {
138
- for (i = 0, l = val.length; i < l; i++) {
139
- result.push(fn.call(this, val[i], i))
140
- }
141
- } else if (typeof val === 'number') {
142
- for (i = 0; i < val; i++) {
143
- result.push(fn.call(this, i + 1, i))
144
- }
145
- } else if (isObject(val)) {
146
- keys = Object.keys(val)
147
- for (i = 0, l = keys.length; i < l; i++) {
148
- key = keys[i]
149
- result.push(fn.call(this, val[key], key, i))
178
+ } else {
179
+ if (hasOwn(children, '__slot')) {
180
+ if (children.__slot === name) result.push(...children)
181
+ } else if (children?.props?.slot === name) {
182
+ result.push(children)
150
183
  }
151
184
  }
185
+ result = result.filter(item => {
186
+ if (!isObject(item) || this.__dispatchedSlotSet.has(item)) return false
187
+ this.__dispatchedSlotSet.add(item)
188
+ return true
189
+ })
190
+ if (!result.length) return null
191
+ result.__slot = slot
152
192
  return result
153
- },
154
- triggerEvent (eventName, eventDetail) {
155
- const props = propsRef.current
156
- const handler = props && (props['bind' + eventName] || props['catch' + eventName] || props['capture-bind' + eventName] || props['capture-catch' + eventName])
157
- if (handler && typeof handler === 'function') {
158
- const timeStamp = +new Date()
159
- const dataset = collectDataset(props)
160
- const id = props.id || ''
161
- const eventObj = {
162
- type: eventName,
163
- timeStamp,
164
- target: {
165
- id,
166
- dataset,
167
- targetDataset: dataset
168
- },
169
- currentTarget: {
170
- id,
171
- dataset
172
- },
173
- detail: eventDetail
174
- }
175
- handler.call(this, eventObj)
176
- }
177
- },
178
- selectComponent (selector) {
179
- return this.__selectRef(selector, 'component')
180
- },
181
- selectAllComponents (selector) {
182
- return this.__selectRef(selector, 'component', true)
183
- },
184
- createSelectorQuery () {
185
- return createSelectorQuery().in(this)
186
- },
187
- createIntersectionObserver (opt) {
188
- return createIntersectionObserver(this, opt, intersectionCtx)
189
- },
190
- ...rawOptions.methods
191
- }, {
193
+ }
194
+ return null
195
+ }
196
+ }
197
+
198
+ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps, components, pageId, intersectionCtx }) {
199
+ const instance = Object.create(instanceProto, {
192
200
  dataset: {
193
201
  get () {
194
202
  const props = propsRef.current
@@ -203,18 +211,55 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps
203
211
  },
204
212
  enumerable: true
205
213
  },
206
- props: {
214
+ __props: {
207
215
  get () {
208
216
  return propsRef.current
209
217
  },
210
- enumerable: true
218
+ enumerable: false
219
+ },
220
+ __pageId: {
221
+ get () {
222
+ return pageId
223
+ },
224
+ enumerable: false
225
+ },
226
+ __intersectionCtx: {
227
+ get () {
228
+ return intersectionCtx
229
+ },
230
+ enumerable: false
231
+ },
232
+ __validProps: {
233
+ get () {
234
+ return validProps
235
+ },
236
+ enumerable: false
237
+ },
238
+ __injectedRender: {
239
+ get () {
240
+ return currentInject.render || noop
241
+ },
242
+ enumerable: false
243
+ },
244
+ __getRefsData: {
245
+ get () {
246
+ return currentInject.getRefsData || noop
247
+ },
248
+ enumerable: false
211
249
  }
212
250
  })
213
251
 
214
- const props = propsRef.current
252
+ // bind this & assign methods
253
+ if (rawOptions.methods) {
254
+ Object.entries(rawOptions.methods).forEach(([key, method]) => {
255
+ instance[key] = method.bind(instance)
256
+ })
257
+ }
215
258
 
216
259
  if (type === 'page') {
260
+ const props = propsRef.current
217
261
  instance.route = props.route.name
262
+ global.__mpxPagesMap = global.__mpxPagesMap || {}
218
263
  global.__mpxPagesMap[props.route.key] = [instance, props.navigation]
219
264
  }
220
265
 
@@ -223,12 +268,10 @@ function createInstance ({ propsRef, type, rawOptions, currentInject, validProps
223
268
 
224
269
  Object.assign(proxy, {
225
270
  onStoreChange: null,
226
- // eslint-disable-next-line symbol-description
227
271
  stateVersion: Symbol(),
228
272
  subscribe: (onStoreChange) => {
229
273
  if (!proxy.effect) {
230
274
  createEffect(proxy, components)
231
- // eslint-disable-next-line symbol-description
232
275
  proxy.stateVersion = Symbol()
233
276
  }
234
277
  proxy.onStoreChange = onStoreChange
@@ -266,8 +309,6 @@ function hasPageHook (mpxProxy, hookNames) {
266
309
  })
267
310
  }
268
311
 
269
- const RouteContext = createContext(null)
270
-
271
312
  const triggerPageStatusHook = (mpxProxy, event) => {
272
313
  mpxProxy.callHook(event === 'show' ? ONSHOW : ONHIDE)
273
314
  const pageLifetimes = mpxProxy.options.pageLifetimes
@@ -297,8 +338,8 @@ function usePageEffect (mpxProxy, pageId) {
297
338
  const hasHideHook = hasPageHook(mpxProxy, [ONHIDE, 'hide'])
298
339
  const hasResizeHook = hasPageHook(mpxProxy, [ONRESIZE, 'resize'])
299
340
  if (hasShowHook || hasHideHook || hasResizeHook) {
300
- if (hasOwn(pageStatusContext, pageId)) {
301
- unWatch = watch(() => pageStatusContext[pageId], (newVal) => {
341
+ if (hasOwn(pageStatusMap, pageId)) {
342
+ unWatch = watch(() => pageStatusMap[pageId], (newVal) => {
302
343
  if (newVal === 'show' || newVal === 'hide') {
303
344
  triggerPageStatusHook(mpxProxy, newVal)
304
345
  } else if (/^resize/.test(newVal)) {
@@ -313,32 +354,28 @@ function usePageEffect (mpxProxy, pageId) {
313
354
  }, [])
314
355
  }
315
356
 
316
- const pageStatusContext = reactive({})
317
357
  let pageId = 0
358
+ const pageStatusMap = global.__mpxPageStatusMap = reactive({})
318
359
 
319
360
  function usePageStatus (navigation, pageId) {
320
- let isFocused = true
321
- set(pageStatusContext, pageId, '')
361
+ navigation.pageId = pageId
362
+ set(pageStatusMap, pageId, '')
322
363
  useEffect(() => {
323
364
  const focusSubscription = navigation.addListener('focus', () => {
324
- pageStatusContext[pageId] = 'show'
325
- isFocused = true
365
+ pageStatusMap[pageId] = 'show'
326
366
  })
327
367
  const blurSubscription = navigation.addListener('blur', () => {
328
- pageStatusContext[pageId] = 'hide'
329
- isFocused = false
368
+ pageStatusMap[pageId] = 'hide'
330
369
  })
331
370
  const unWatchAppFocusedState = watch(global.__mpxAppFocusedState, (value) => {
332
- if (isFocused) {
333
- pageStatusContext[pageId] = value
334
- }
371
+ pageStatusMap[pageId] = value
335
372
  })
336
373
 
337
374
  return () => {
338
375
  focusSubscription()
339
376
  blurSubscription()
340
377
  unWatchAppFocusedState()
341
- del(pageStatusContext, pageId)
378
+ del(pageStatusMap, pageId)
342
379
  }
343
380
  }, [navigation])
344
381
  }
@@ -347,6 +384,7 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
347
384
  rawOptions = mergeOptions(rawOptions, type, false)
348
385
  const components = Object.assign({}, rawOptions.components, currentInject.getComponents())
349
386
  const validProps = Object.assign({}, rawOptions.props, rawOptions.properties)
387
+ if (rawOptions.methods) rawOptions.methods = wrapMethodsWithErrorHandling(rawOptions.methods)
350
388
  const defaultOptions = memo(forwardRef((props, ref) => {
351
389
  const instanceRef = useRef(null)
352
390
  const propsRef = useRef(null)
@@ -365,22 +403,37 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
365
403
 
366
404
  const proxy = instance.__mpxProxy
367
405
 
368
- proxy.callHook(REACTHOOKSEXEC)
369
-
370
- useEffect(() => {
371
- if (!isFirst) {
372
- // 处理props更新
373
- Object.keys(validProps).forEach((key) => {
374
- if (hasOwn(props, key)) {
375
- instance[key] = props[key]
376
- } else {
377
- const altKey = hump2dash(key)
378
- if (hasOwn(props, altKey)) {
379
- instance[key] = props[altKey]
380
- }
406
+ let hooksResult = proxy.callHook(REACTHOOKSEXEC, [props])
407
+ if (isObject(hooksResult)) {
408
+ hooksResult = wrapMethodsWithErrorHandling(hooksResult, proxy)
409
+ if (isFirst) {
410
+ const onConflict = proxy.createProxyConflictHandler('react hooks result')
411
+ Object.keys(hooksResult).forEach((key) => {
412
+ if (key in proxy.target) {
413
+ onConflict(key)
381
414
  }
415
+ proxy.target[key] = hooksResult[key]
382
416
  })
417
+ } else {
418
+ Object.assign(proxy.target, hooksResult)
383
419
  }
420
+ }
421
+
422
+ if (!isFirst) {
423
+ // 处理props更新
424
+ Object.keys(validProps).forEach((key) => {
425
+ if (hasOwn(props, key)) {
426
+ instance[key] = props[key]
427
+ } else {
428
+ const altKey = hump2dash(key)
429
+ if (hasOwn(props, altKey)) {
430
+ instance[key] = props[altKey]
431
+ }
432
+ }
433
+ })
434
+ }
435
+
436
+ useEffect(() => {
384
437
  if (proxy.pendingUpdatedFlag) {
385
438
  proxy.pendingUpdatedFlag = false
386
439
  proxy.callHook(UPDATED)
@@ -391,6 +444,9 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
391
444
 
392
445
  useEffect(() => {
393
446
  if (type === 'page') {
447
+ if (!global.__mpxAppLaunched && global.__mpxAppOnLaunch) {
448
+ global.__mpxAppOnLaunch(props.navigation)
449
+ }
394
450
  proxy.callHook(ONLOAD, [props.route.params || {}])
395
451
  }
396
452
  proxy.mounted()
@@ -405,10 +461,21 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
405
461
 
406
462
  useSyncExternalStore(proxy.subscribe, proxy.getSnapshot)
407
463
 
408
- const root = rawOptions.options?.disableMemo ? proxy.effect.run() : useMemo(() => proxy.effect.run(), [proxy.stateVersion])
409
- if (root) {
464
+ if ((rawOptions.options?.disableMemo)) {
465
+ proxy.memoVersion = Symbol()
466
+ }
467
+
468
+ const finalMemoVersion = useMemo(() => {
469
+ if (!hasPendingJob(proxy.update)) {
470
+ proxy.finalMemoVersion = Symbol()
471
+ }
472
+ return proxy.finalMemoVersion
473
+ }, [proxy.stateVersion, proxy.memoVersion])
474
+
475
+ const root = useMemo(() => proxy.effect.run(), [finalMemoVersion])
476
+ if (root && root.props.ishost) {
410
477
  const rootProps = getRootProps(props)
411
- rootProps.style = { ...root.props.style, ...rootProps.style }
478
+ rootProps.style = Object.assign({}, root.props.style, rootProps.style)
412
479
  // update root props
413
480
  return cloneElement(root, rootProps)
414
481
  }
@@ -423,35 +490,27 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
423
490
  const { Provider, useSafeAreaInsets, GestureHandlerRootView } = global.__navigationHelper
424
491
  const pageConfig = Object.assign({}, global.__mpxPageConfig, currentInject.pageConfig)
425
492
  const Page = ({ navigation, route }) => {
493
+ const [enabled, setEnabled] = useState(true)
426
494
  const currentPageId = useMemo(() => ++pageId, [])
427
495
  const intersectionObservers = useRef({})
428
496
  usePageStatus(navigation, currentPageId)
429
497
 
430
498
  useLayoutEffect(() => {
431
499
  const isCustom = pageConfig.navigationStyle === 'custom'
432
- let opt = {}
433
- if (__mpx_mode__ === 'android') {
434
- opt = {
435
- statusBarTranslucent: isCustom,
436
- statusBarStyle: pageConfig.statusBarStyle, // 枚举值 'auto' | 'dark' | 'light' 控制statusbar字体颜色
437
- statusBarColor: isCustom ? 'transparent' : pageConfig.statusBarColor // 控制statusbar背景颜色
438
- }
439
- } else if (__mpx_mode__ === 'ios') {
440
- opt = {
441
- headerBackTitleVisible: false
442
- }
443
- }
444
500
  navigation.setOptions({
445
501
  headerShown: !isCustom,
446
- headerShadowVisible: false,
447
- headerTitle: pageConfig.navigationBarTitleText || '',
502
+ title: pageConfig.navigationBarTitleText || '',
448
503
  headerStyle: {
449
504
  backgroundColor: pageConfig.navigationBarBackgroundColor || '#000000'
450
505
  },
451
- headerTitleAlign: 'center',
452
- headerTintColor: pageConfig.navigationBarTextStyle || 'white',
453
- ...opt
506
+ headerTintColor: pageConfig.navigationBarTextStyle || 'white'
454
507
  })
508
+ if (__mpx_mode__ === 'android') {
509
+ ReactNative.StatusBar.setBarStyle(pageConfig.barStyle || 'dark-content')
510
+ ReactNative.StatusBar.setTranslucent(isCustom) // 控制statusbar是否占位
511
+ const color = isCustom ? 'transparent' : pageConfig.statusBarColor
512
+ color && ReactNative.StatusBar.setBackgroundColor(color)
513
+ }
455
514
  }, [])
456
515
 
457
516
  const rootRef = useRef(null)
@@ -461,6 +520,30 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
461
520
  })
462
521
  }, [])
463
522
 
523
+ const withKeyboardAvoidingView = (element) => {
524
+ if (__mpx_mode__ === 'ios') {
525
+ return createElement(KeyboardAvoidContext.Provider,
526
+ {
527
+ value: setEnabled
528
+ },
529
+ createElement(ReactNative.KeyboardAvoidingView,
530
+ {
531
+ style: {
532
+ flex: 1
533
+ },
534
+ contentContainerStyle: {
535
+ flex: 1
536
+ },
537
+ behavior: 'position',
538
+ enabled
539
+ },
540
+ element
541
+ )
542
+ )
543
+ }
544
+ return element
545
+ }
546
+
464
547
  navigation.insets = useSafeAreaInsets()
465
548
 
466
549
  return createElement(GestureHandlerRootView,
@@ -469,37 +552,40 @@ export function getDefaultOptions ({ type, rawOptions = {}, currentInject }) {
469
552
  flex: 1
470
553
  }
471
554
  },
472
- createElement(ReactNative.View, {
473
- style: {
474
- flex: 1,
475
- backgroundColor: pageConfig.backgroundColor || '#ffffff'
476
- },
477
- ref: rootRef,
478
- onLayout
479
- },
480
- createElement(Provider,
481
- null,
555
+ withKeyboardAvoidingView(
556
+ createElement(ReactNative.View,
557
+ {
558
+ style: {
559
+ flex: 1,
560
+ backgroundColor: pageConfig.backgroundColor || '#ffffff'
561
+ },
562
+ ref: rootRef,
563
+ onLayout
564
+ },
482
565
  createElement(RouteContext.Provider,
483
566
  {
484
567
  value: currentPageId
485
568
  },
486
569
  createElement(IntersectionObserverContext.Provider,
487
- {
488
- value: intersectionObservers.current
489
- },
490
- createElement(defaultOptions,
491
- {
492
- navigation,
493
- route,
494
- id: currentPageId
495
- }
570
+ {
571
+ value: intersectionObservers.current
572
+ },
573
+ createElement(Provider,
574
+ null,
575
+ createElement(defaultOptions,
576
+ {
577
+ navigation,
578
+ route,
579
+ id: currentPageId
580
+ }
581
+ )
496
582
  )
497
583
  )
498
584
  )
499
585
  )
500
586
  )
501
- // todo custom portal host for active route
502
587
  )
588
+ // todo custom portal host for active route
503
589
  }
504
590
  return Page
505
591
  }