@mpxjs/webpack-plugin 2.10.6-beta.8 → 2.10.6-beta.9

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.
@@ -44,6 +44,7 @@ const fixComponentName = require('./fix-component-name')
44
44
  const rootPortal = require('./root-portal')
45
45
  const stickyHeader = require('./sticky-header')
46
46
  const stickySection = require('./sticky-section')
47
+ const navContainer = require('./nav-container')
47
48
 
48
49
  module.exports = function getComponentConfigs ({ warn, error }) {
49
50
  /**
@@ -129,6 +130,7 @@ module.exports = function getComponentConfigs ({ warn, error }) {
129
130
  component(),
130
131
  rootPortal({ print }),
131
132
  stickyHeader({ print }),
132
- stickySection({ print })
133
+ stickySection({ print }),
134
+ navContainer({ print })
133
135
  ]
134
136
  }
@@ -0,0 +1,27 @@
1
+ const TAG_NAME = 'nav-container'
2
+
3
+ module.exports = function ({ print }) {
4
+ return {
5
+ test: TAG_NAME,
6
+ web(tag, { el }) {
7
+ el.isBuiltIn = true
8
+ return 'mpx-nav-container'
9
+ },
10
+ ios(tag, { el }) {
11
+ el.isBuiltIn = true
12
+ return 'mpx-nav-container'
13
+ },
14
+ android(tag, { el }) {
15
+ el.isBuiltIn = true
16
+ return 'mpx-nav-container'
17
+ },
18
+ harmony(tag, { el }) {
19
+ el.isBuiltIn = true
20
+ return 'mpx-nav-container'
21
+ },
22
+ wx(tag, { el }) {
23
+ el.isBuiltIn = true
24
+ return 'mpx-nav-container'
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <slot />
3
+ </template>
@@ -12,7 +12,6 @@ export type KeyboardAvoidContextValue = MutableRefObject<{
12
12
  adjustPosition: boolean
13
13
  keyboardHeight?: number
14
14
  onKeyboardShow?: () => void
15
- blurCallbacks: (() => void)[]
16
15
  } | null>
17
16
 
18
17
  export interface GroupValue {
@@ -42,13 +41,13 @@ export interface IntersectionObserver {
42
41
  }
43
42
 
44
43
  export interface PortalContextValue {
45
- mount: (children: React.ReactNode, key?: number | null, id?: number| null) => number| undefined
44
+ mount: (children: React.ReactNode, key?: number | null, id?: number | null) => number | undefined
46
45
  update: (key: number, children: React.ReactNode) => void
47
46
  unmount: (key: number) => void
48
47
  }
49
48
 
50
49
  export interface ScrollViewContextValue {
51
- gestureRef: React.RefObject<any> | null,
50
+ gestureRef: React.RefObject<any> | null
52
51
  scrollOffset: Animated.Value
53
52
  }
54
53
 
@@ -58,10 +57,15 @@ export interface RouteContextValue {
58
57
  }
59
58
 
60
59
  export interface StickyContextValue {
61
- registerStickyHeader: Function,
60
+ registerStickyHeader: Function
62
61
  unregisterStickyHeader: Function
63
62
  }
64
63
 
64
+ export interface NavSharedValue {
65
+ customNav?: React.ReactNode
66
+ setCustomNav: (value: React.ReactNode) => void
67
+ }
68
+
65
69
  export const MovableAreaContext = createContext({ width: 0, height: 0 })
66
70
 
67
71
  export const FormContext = createContext<FormContextValue | null>(null)
@@ -89,3 +93,5 @@ export const ScrollViewContext = createContext<ScrollViewContextValue>({ gesture
89
93
  export const PortalContext = createContext<PortalContextValue>(null as any)
90
94
 
91
95
  export const StickyContext = createContext<StickyContextValue>({ registerStickyHeader: noop, unregisterStickyHeader: noop })
96
+
97
+ export const NavSharedContext = createContext<NavSharedValue>(null as any)
@@ -9,7 +9,6 @@ export type KeyboardAvoidContextValue = MutableRefObject<{
9
9
  adjustPosition: boolean;
10
10
  keyboardHeight?: number;
11
11
  onKeyboardShow?: () => void;
12
- blurCallbacks: (() => void)[];
13
12
  } | null>;
14
13
  export interface GroupValue {
15
14
  [key: string]: {
@@ -55,6 +54,10 @@ export interface StickyContextValue {
55
54
  registerStickyHeader: Function;
56
55
  unregisterStickyHeader: Function;
57
56
  }
57
+ export interface NavSharedValue {
58
+ customNav?: React.ReactNode;
59
+ setCustomNav: (value: React.ReactNode) => void;
60
+ }
58
61
  export declare const MovableAreaContext: import("react").Context<{
59
62
  width: number;
60
63
  height: number;
@@ -72,3 +75,4 @@ export declare const KeyboardAvoidContext: import("react").Context<KeyboardAvoid
72
75
  export declare const ScrollViewContext: import("react").Context<ScrollViewContextValue>;
73
76
  export declare const PortalContext: import("react").Context<PortalContextValue>;
74
77
  export declare const StickyContext: import("react").Context<StickyContextValue>;
78
+ export declare const NavSharedContext: import("react").Context<NavSharedValue>;
@@ -15,3 +15,4 @@ export const KeyboardAvoidContext = createContext(null);
15
15
  export const ScrollViewContext = createContext({ gestureRef: null, scrollOffset: new Animated.Value(0) });
16
16
  export const PortalContext = createContext(null);
17
17
  export const StickyContext = createContext({ registerStickyHeader: noop, unregisterStickyHeader: noop });
18
+ export const NavSharedContext = createContext(null);
@@ -145,7 +145,7 @@ const Input = forwardRef((props, ref) => {
145
145
  };
146
146
  const setKeyboardAvoidContext = () => {
147
147
  if (keyboardAvoid) {
148
- keyboardAvoid.current = { cursorSpacing, ref: nodeRef, adjustPosition, blurCallbacks: [] };
148
+ keyboardAvoid.current = { cursorSpacing, ref: nodeRef, adjustPosition };
149
149
  }
150
150
  };
151
151
  const onTouchStart = () => {
@@ -164,7 +164,7 @@ const Input = forwardRef((props, ref) => {
164
164
  bindfocus(getCustomEvent('focus', evt, {
165
165
  detail: {
166
166
  value: tmpValue.current || '',
167
- height: keyboardAvoid.current?.keyboardHeight
167
+ height: keyboardAvoid.current?.keyboardHeight,
168
168
  },
169
169
  layoutRef
170
170
  }, props));
@@ -184,7 +184,6 @@ const Input = forwardRef((props, ref) => {
184
184
  }
185
185
  };
186
186
  const onBlur = (evt) => {
187
- keyboardAvoid?.current?.blurCallbacks.forEach(fn => fn());
188
187
  bindblur && bindblur(getCustomEvent('blur', evt, {
189
188
  detail: {
190
189
  value: tmpValue.current || '',
@@ -1,7 +1,6 @@
1
1
  import React, { useContext, useEffect } from 'react';
2
2
  import { Keyboard, View } from 'react-native';
3
3
  import Animated, { useSharedValue, useAnimatedStyle, withTiming, Easing } from 'react-native-reanimated';
4
- import { getWindowInfo } from '@mpxjs/api-proxy';
5
4
  import { KeyboardAvoidContext } from './context';
6
5
  import { isIOS } from './utils';
7
6
  const KeyboardAvoidingView = ({ children, style, contentContainerStyle, navigation }) => {
@@ -11,7 +10,8 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle, navigati
11
10
  const basic = useSharedValue('auto');
12
11
  const keyboardAvoid = useContext(KeyboardAvoidContext);
13
12
  const animatedStyle = useAnimatedStyle(() => ({
14
- transform: [{ translateY: -offset.value }],
13
+ // translate/position top可能会导致地步渲染区域缺失
14
+ marginTop: -offset.value,
15
15
  flexBasis: basic.value
16
16
  }));
17
17
  const resetKeyboard = () => {
@@ -22,11 +22,6 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle, navigati
22
22
  inputRef.blur();
23
23
  }
24
24
  keyboardAvoid.current = null;
25
- navigation.setPageConfig({
26
- animatedNavStyle: {
27
- top: withTiming(0, { duration: 100, easing: Easing.in(Easing.bezierFn(0.51, 1.18, 0.97, 0.94)) })
28
- }
29
- });
30
25
  }
31
26
  offset.value = withTiming(0, { duration, easing });
32
27
  basic.value = 'auto';
@@ -54,7 +49,7 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle, navigati
54
49
  const aboveValue = -aboveOffset >= cursorSpacing ? 0 : aboveOffset + cursorSpacing;
55
50
  const belowValue = Math.min(endCoordinates.height, aboveOffset + cursorSpacing);
56
51
  const value = aboveOffset > 0 ? belowValue : aboveValue;
57
- offset.value = withTiming(value, { duration, easing }, (finished) => {
52
+ offset.value = withTiming(value, { duration, easing }, finished => {
58
53
  if (finished) {
59
54
  // Set flexBasic after animation to trigger re-layout and reset layout information
60
55
  basic.value = '99.99%';
@@ -74,39 +69,22 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle, navigati
74
69
  return;
75
70
  const { endCoordinates } = evt;
76
71
  const { ref, cursorSpacing = 0, adjustPosition, onKeyboardShow } = keyboardAvoid.current;
77
- // android 上键盘消失只能使用 keyboardDidHide 事件,对于需要和键盘一起改变位置的 nav 来说
78
- // keyboardDidHide 是比较晚的,从动画上看也并不同步,因此采用比较早的blur
79
- keyboardAvoid.current.blurCallbacks.push(resetKeyboard);
80
72
  keyboardAvoid.current.keyboardHeight = endCoordinates.height;
81
73
  onKeyboardShow?.();
82
- if (adjustPosition) {
83
- ref?.current?.measure((x, y, width, height, pageX, pageY) => {
84
- const screenHeightRatio = getWindowInfo().screenHeight /
85
- (endCoordinates.screenY + endCoordinates.height);
86
- const navAboveOffset = pageY + height - Math.floor(endCoordinates.screenY * screenHeightRatio);
87
- const aboveOffset = pageY + height - endCoordinates.screenY;
88
- const belowOffset = endCoordinates.height - aboveOffset;
89
- const aboveValue = -aboveOffset >= cursorSpacing ? 0 : aboveOffset + cursorSpacing;
90
- const belowValue = Math.min(belowOffset, cursorSpacing);
91
- const value = aboveOffset > 0 ? belowValue : aboveValue;
92
- navigation.setPageConfig({
93
- animatedNavStyle: {
94
- // android 手机本身支持将页面整体上移(包含 nav 和 body)
95
- // mpx-keyboard-avoiding-view 和 nav 使用 transform 时互不影响,因此这里只需要计算 android 键盘出现导致上移的高度即可
96
- top: withTiming(navAboveOffset, {
97
- duration: 100,
98
- easing
99
- })
100
- }
101
- });
102
- offset.value = withTiming(value, { duration, easing }, (finished) => {
74
+ ref?.current?.measure((x, y, width, height, pageX, pageY) => {
75
+ const aboveOffset = offset.value + pageY + height - endCoordinates.screenY;
76
+ const aboveValue = -aboveOffset >= cursorSpacing ? 0 : aboveOffset + cursorSpacing;
77
+ const belowValue = Math.min(endCoordinates.height, aboveOffset + cursorSpacing);
78
+ const value = aboveOffset > 0 ? belowValue : aboveValue;
79
+ if (adjustPosition) {
80
+ offset.value = withTiming(value, { duration, easing }, finished => {
103
81
  if (finished) {
104
82
  // Set flexBasic after animation to trigger re-layout and reset layout information
105
83
  basic.value = '99.99%';
106
84
  }
107
85
  });
108
- });
109
- }
86
+ }
87
+ });
110
88
  }),
111
89
  Keyboard.addListener('keyboardDidHide', resetKeyboard)
112
90
  ];
@@ -116,12 +94,7 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle, navigati
116
94
  };
117
95
  }, [keyboardAvoid]);
118
96
  return (<View style={style} onTouchEnd={onTouchEnd} onTouchMove={onTouchEnd}>
119
- <Animated.View style={[
120
- contentContainerStyle,
121
- animatedStyle
122
- ]}>
123
- {children}
124
- </Animated.View>
97
+ <Animated.View style={[contentContainerStyle, animatedStyle]}>{children}</Animated.View>
125
98
  </View>);
126
99
  };
127
100
  KeyboardAvoidingView.displayName = 'MpxKeyboardAvoidingView';
@@ -0,0 +1,9 @@
1
+ /// <reference types="react" />
2
+ interface MpxNavContainerProps {
3
+ children?: React.ReactNode;
4
+ }
5
+ export default function MpxNavContainer(props: MpxNavContainerProps): import("react").ReactNode;
6
+ export declare function NavSharedProvider({ children }: {
7
+ children?: React.ReactNode;
8
+ }): import("react").JSX.Element;
9
+ export {};
@@ -0,0 +1,23 @@
1
+ import { useNavShared } from './useNavShared';
2
+ import { NavSharedContext } from './context';
3
+ import { useLayoutEffect, useMemo, useState } from 'react';
4
+ import { isAndroid } from './utils';
5
+ export default function MpxNavContainer(props) {
6
+ const [, setCustomNav] = useNavShared();
7
+ useLayoutEffect(() => {
8
+ if (!isAndroid)
9
+ return;
10
+ if (props.children) {
11
+ setCustomNav(props.children);
12
+ }
13
+ return () => {
14
+ setCustomNav(undefined);
15
+ };
16
+ }, [props.children]);
17
+ return isAndroid ? null : props.children;
18
+ }
19
+ export function NavSharedProvider({ children }) {
20
+ const [customNav, setCustomNav] = useState();
21
+ const value = useMemo(() => ({ customNav, setCustomNav }), [customNav]);
22
+ return <NavSharedContext.Provider value={value}>{children}</NavSharedContext.Provider>;
23
+ }
@@ -2,7 +2,7 @@
2
2
  import { createElement, useState, useMemo, memo } from 'react';
3
3
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
4
4
  import { StatusBar, processColor, TouchableWithoutFeedback, Image, View, StyleSheet, Text } from 'react-native';
5
- import Animated, { useSharedValue, useAnimatedStyle, withTiming, Easing } from 'react-native-reanimated';
5
+ import { useNavShared } from './useNavShared';
6
6
  function convertToHex(color) {
7
7
  try {
8
8
  const intColor = processColor(color);
@@ -83,16 +83,10 @@ function createMpxNav(options) {
83
83
  const { Mpx } = options;
84
84
  const innerNav = memo(({ pageConfig, navigation }) => {
85
85
  const [innerPageConfig, setPageConfig] = useState(pageConfig || {});
86
- const translateY = useSharedValue(0);
86
+ const [customNav] = useNavShared();
87
87
  const safeAreaTop = useSafeAreaInsets()?.top || 0;
88
- const animatedStyle = useAnimatedStyle(() => ({
89
- transform: [{ translateY: translateY.value }]
90
- }));
91
88
  navigation.setPageConfig = (config) => {
92
- const newConfig = Object.assign({}, innerPageConfig, config);
93
- translateY.value =
94
- newConfig?.animatedNavStyle?.top ?? withTiming(0, { duration: 100, easing: Easing.in(Easing.bezierFn(0.51, 1.18, 0.97, 0.94)) });
95
- setPageConfig(newConfig);
89
+ setPageConfig(Object.assign({}, innerPageConfig, config));
96
90
  };
97
91
  const isCustom = innerPageConfig.navigationStyle === 'custom';
98
92
  const navigationBarTextStyle = useMemo(() => validBarTextStyle(innerPageConfig.navigationBarTextStyle), [innerPageConfig.navigationBarTextStyle]);
@@ -104,7 +98,10 @@ function createMpxNav(options) {
104
98
  barStyle: navigationBarTextStyle === NavColor.White ? 'light-content' : 'dark-content' // 'default'/'light-content'/'dark-content'
105
99
  });
106
100
  if (isCustom)
107
- return statusBarElement;
101
+ return (<>
102
+ {statusBarElement}
103
+ {customNav}
104
+ </>);
108
105
  // 假设是栈导航,获取栈的长度
109
106
  const stackLength = navigation.getState()?.routes?.length;
110
107
  const onStackTopBack = Mpx.config?.rnConfig?.onStackTopBack;
@@ -124,28 +121,24 @@ function createMpxNav(options) {
124
121
  </View>
125
122
  </TouchableWithoutFeedback>)
126
123
  : null;
127
- return (
128
- // 不设置 zIndex transform 无法生效
129
- <Animated.View style={[{ position: 'relative', zIndex: 10000 }, animatedStyle]}>
130
- <View style={[
124
+ return (<View style={[
131
125
  styles.header,
132
126
  {
133
127
  paddingTop: safeAreaTop,
134
128
  backgroundColor: innerPageConfig.navigationBarBackgroundColor || '#000000'
135
129
  }
136
130
  ]}>
137
- {statusBarElement}
138
- {/* TODO: 确定 height 的有效性 */}
139
- {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
140
- {/* @ts-expect-error */}
141
- <View style={styles.headerContent} height={titleHeight}>
142
- {backElement}
143
- <Text style={[styles.title, { color: navigationBarTextStyle }]} numberOfLines={1}>
144
- {innerPageConfig.navigationBarTitleText?.trim() || ''}
145
- </Text>
146
- </View>
131
+ {statusBarElement}
132
+ {/* TODO: 确定 height 的有效性 */}
133
+ {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
134
+ {/* @ts-expect-error */}
135
+ <View style={styles.headerContent} height={titleHeight}>
136
+ {backElement}
137
+ <Text style={[styles.title, { color: navigationBarTextStyle }]} numberOfLines={1}>
138
+ {innerPageConfig.navigationBarTitleText?.trim() || ''}
139
+ </Text>
147
140
  </View>
148
- </Animated.View>);
141
+ </View>);
149
142
  // return createElement(
150
143
  // Animated.View,
151
144
  // {
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare function useNavShared(): readonly [import("react").ReactNode, (value: import("react").ReactNode) => void];
@@ -0,0 +1,6 @@
1
+ import { useContext } from 'react';
2
+ import { NavSharedContext } from './context';
3
+ export function useNavShared() {
4
+ const navSharedValue = useContext(NavSharedContext);
5
+ return [navSharedValue.customNav, navSharedValue.setCustomNav];
6
+ }
@@ -281,7 +281,7 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
281
281
 
282
282
  const setKeyboardAvoidContext = () => {
283
283
  if (keyboardAvoid) {
284
- keyboardAvoid.current = { cursorSpacing, ref: nodeRef, adjustPosition, blurCallbacks: [] }
284
+ keyboardAvoid.current = { cursorSpacing, ref: nodeRef, adjustPosition }
285
285
  }
286
286
  }
287
287
 
@@ -298,6 +298,7 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
298
298
  if (!keyboardAvoid?.current) {
299
299
  setKeyboardAvoidContext()
300
300
  }
301
+
301
302
  if (bindfocus && keyboardAvoid?.current) {
302
303
  const focusAction = () => {
303
304
  bindfocus(
@@ -307,7 +308,7 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
307
308
  {
308
309
  detail: {
309
310
  value: tmpValue.current || '',
310
- height: keyboardAvoid.current?.keyboardHeight
311
+ height: keyboardAvoid.current?.keyboardHeight,
311
312
  },
312
313
  layoutRef
313
314
  },
@@ -330,7 +331,6 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
330
331
  }
331
332
 
332
333
  const onBlur = (evt: NativeSyntheticEvent<TextInputFocusEventData>) => {
333
- keyboardAvoid?.current?.blurCallbacks.forEach(fn => fn())
334
334
  bindblur && bindblur(
335
335
  getCustomEvent(
336
336
  'blur',
@@ -1,7 +1,6 @@
1
1
  import React, { ReactNode, useContext, useEffect } from 'react'
2
2
  import { DimensionValue, EmitterSubscription, Keyboard, View, ViewStyle, NativeSyntheticEvent, NativeTouchEvent } from 'react-native'
3
3
  import Animated, { useSharedValue, useAnimatedStyle, withTiming, Easing } from 'react-native-reanimated'
4
- import { getWindowInfo } from '@mpxjs/api-proxy'
5
4
  import { KeyboardAvoidContext } from './context'
6
5
  import { isIOS } from './utils'
7
6
 
@@ -21,7 +20,8 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle, navigati
21
20
  const keyboardAvoid = useContext(KeyboardAvoidContext)
22
21
 
23
22
  const animatedStyle = useAnimatedStyle(() => ({
24
- transform: [{ translateY: -offset.value }],
23
+ // translate/position top可能会导致地步渲染区域缺失
24
+ marginTop: -offset.value,
25
25
  flexBasis: basic.value as DimensionValue
26
26
  }))
27
27
 
@@ -33,11 +33,6 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle, navigati
33
33
  inputRef.blur()
34
34
  }
35
35
  keyboardAvoid.current = null
36
- navigation.setPageConfig({
37
- animatedNavStyle: {
38
- top: withTiming(0, { duration: 100, easing: Easing.in(Easing.bezierFn(0.51, 1.18, 0.97, 0.94)) })
39
- }
40
- })
41
36
  }
42
37
  offset.value = withTiming(0, { duration, easing })
43
38
  basic.value = 'auto'
@@ -67,7 +62,7 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle, navigati
67
62
  const aboveValue = -aboveOffset >= cursorSpacing ? 0 : aboveOffset + cursorSpacing
68
63
  const belowValue = Math.min(endCoordinates.height, aboveOffset + cursorSpacing)
69
64
  const value = aboveOffset > 0 ? belowValue : aboveValue
70
- offset.value = withTiming(value, { duration, easing }, (finished) => {
65
+ offset.value = withTiming(value, { duration, easing }, finished => {
71
66
  if (finished) {
72
67
  // Set flexBasic after animation to trigger re-layout and reset layout information
73
68
  basic.value = '99.99%'
@@ -85,43 +80,23 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle, navigati
85
80
  if (!keyboardAvoid?.current) return
86
81
  const { endCoordinates } = evt
87
82
  const { ref, cursorSpacing = 0, adjustPosition, onKeyboardShow } = keyboardAvoid.current
88
- // android 上键盘消失只能使用 keyboardDidHide 事件,对于需要和键盘一起改变位置的 nav 来说
89
- // keyboardDidHide 是比较晚的,从动画上看也并不同步,因此采用比较早的blur
90
- keyboardAvoid.current.blurCallbacks.push(resetKeyboard)
91
83
  keyboardAvoid.current.keyboardHeight = endCoordinates.height
92
84
  onKeyboardShow?.()
93
- if (adjustPosition) {
94
- ref?.current?.measure((x: number, y: number, width: number, height: number, pageX: number, pageY: number) => {
95
- const screenHeightRatio =
96
- getWindowInfo().screenHeight /
97
- (endCoordinates.screenY + endCoordinates.height)
98
- const navAboveOffset = pageY + height - Math.floor(endCoordinates.screenY * screenHeightRatio)
99
-
100
- const aboveOffset = pageY + height - endCoordinates.screenY
101
- const belowOffset = endCoordinates.height - aboveOffset
102
- const aboveValue = -aboveOffset >= cursorSpacing ? 0 : aboveOffset + cursorSpacing
103
- const belowValue = Math.min(belowOffset, cursorSpacing)
104
- const value = aboveOffset > 0 ? belowValue : aboveValue
85
+ ref?.current?.measure((x: number, y: number, width: number, height: number, pageX: number, pageY: number) => {
86
+ const aboveOffset = offset.value + pageY + height - endCoordinates.screenY
87
+ const aboveValue = -aboveOffset >= cursorSpacing ? 0 : aboveOffset + cursorSpacing
88
+ const belowValue = Math.min(endCoordinates.height, aboveOffset + cursorSpacing)
89
+ const value = aboveOffset > 0 ? belowValue : aboveValue
105
90
 
106
- navigation.setPageConfig({
107
- animatedNavStyle: {
108
- // android 手机本身支持将页面整体上移(包含 nav 和 body)
109
- // mpx-keyboard-avoiding-view 和 nav 使用 transform 时互不影响,因此这里只需要计算 android 键盘出现导致上移的高度即可
110
- top: withTiming(navAboveOffset, {
111
- duration: 100,
112
- easing
113
- })
114
- }
115
- })
116
-
117
- offset.value = withTiming(value, { duration, easing }, (finished) => {
91
+ if (adjustPosition) {
92
+ offset.value = withTiming(value, { duration, easing }, finished => {
118
93
  if (finished) {
119
94
  // Set flexBasic after animation to trigger re-layout and reset layout information
120
95
  basic.value = '99.99%'
121
96
  }
122
97
  })
123
- })
124
- }
98
+ }
99
+ })
125
100
  }),
126
101
  Keyboard.addListener('keyboardDidHide', resetKeyboard)
127
102
  ]
@@ -134,14 +109,7 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle, navigati
134
109
 
135
110
  return (
136
111
  <View style={style} onTouchEnd={onTouchEnd} onTouchMove={onTouchEnd}>
137
- <Animated.View
138
- style={[
139
- contentContainerStyle,
140
- animatedStyle
141
- ]}
142
- >
143
- {children}
144
- </Animated.View>
112
+ <Animated.View style={[contentContainerStyle, animatedStyle]}>{children}</Animated.View>
145
113
  </View>
146
114
  )
147
115
  }
@@ -0,0 +1,33 @@
1
+ import { AnimatedStyle } from 'react-native-reanimated'
2
+ import { useNavShared } from './useNavShared'
3
+ import { NavSharedContext, NavSharedValue } from './context'
4
+ import { useLayoutEffect, useMemo, useState } from 'react'
5
+ import { StyleProp } from 'react-native'
6
+ import { isAndroid } from './utils'
7
+
8
+ interface MpxNavContainerProps {
9
+ children?: React.ReactNode
10
+ }
11
+
12
+ export default function MpxNavContainer(props: MpxNavContainerProps) {
13
+ const [, setCustomNav] = useNavShared()
14
+
15
+ useLayoutEffect(() => {
16
+ if (!isAndroid) return
17
+ if (props.children) {
18
+ setCustomNav(props.children)
19
+ }
20
+
21
+ return () => {
22
+ setCustomNav(undefined)
23
+ }
24
+ }, [props.children])
25
+
26
+ return isAndroid ? null : props.children
27
+ }
28
+
29
+ export function NavSharedProvider({ children }: { children?: React.ReactNode }) {
30
+ const [customNav, setCustomNav] = useState()
31
+ const value = useMemo(() => ({ customNav, setCustomNav } as NavSharedValue), [customNav])
32
+ return <NavSharedContext.Provider value={value}>{children}</NavSharedContext.Provider>
33
+ }
@@ -1,8 +1,8 @@
1
1
  /* eslint-disable space-before-function-paren */
2
- import { createElement, useState, useMemo, memo } from 'react'
2
+ import { createElement, useState, useMemo, memo, useContext, useLayoutEffect } from 'react'
3
3
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
4
4
  import { StatusBar, processColor, TouchableWithoutFeedback, Image, View, StyleSheet, Text } from 'react-native'
5
- import Animated, { useSharedValue, useAnimatedStyle, withTiming, Easing } from 'react-native-reanimated'
5
+ import { useNavShared } from './useNavShared'
6
6
 
7
7
  function convertToHex(color?: string) {
8
8
  try {
@@ -95,19 +95,11 @@ function createMpxNav(options: MpxNavFactorOptions) {
95
95
  const { Mpx } = options
96
96
  const innerNav = memo(({ pageConfig, navigation }: MpxNavProps) => {
97
97
  const [innerPageConfig, setPageConfig] = useState<PageConfig>(pageConfig || {})
98
-
99
- const translateY = useSharedValue(0)
98
+ const [customNav] = useNavShared()
100
99
  const safeAreaTop = useSafeAreaInsets()?.top || 0
101
100
 
102
- const animatedStyle = useAnimatedStyle(() => ({
103
- transform: [{ translateY: translateY.value }]
104
- }))
105
-
106
101
  navigation.setPageConfig = (config: PageConfig) => {
107
- const newConfig = Object.assign({}, innerPageConfig, config)
108
- translateY.value =
109
- newConfig?.animatedNavStyle?.top ?? withTiming(0, { duration: 100, easing: Easing.in(Easing.bezierFn(0.51, 1.18, 0.97, 0.94)) })
110
- setPageConfig(newConfig)
102
+ setPageConfig(Object.assign({}, innerPageConfig, config))
111
103
  }
112
104
  const isCustom = innerPageConfig.navigationStyle === 'custom'
113
105
  const navigationBarTextStyle = useMemo(() => validBarTextStyle(innerPageConfig.navigationBarTextStyle), [innerPageConfig.navigationBarTextStyle])
@@ -124,7 +116,13 @@ function createMpxNav(options: MpxNavFactorOptions) {
124
116
  barStyle: navigationBarTextStyle === NavColor.White ? 'light-content' : 'dark-content' // 'default'/'light-content'/'dark-content'
125
117
  })
126
118
 
127
- if (isCustom) return statusBarElement
119
+ if (isCustom)
120
+ return (
121
+ <>
122
+ {statusBarElement}
123
+ {customNav}
124
+ </>
125
+ )
128
126
  // 假设是栈导航,获取栈的长度
129
127
  const stackLength = navigation.getState()?.routes?.length
130
128
  const onStackTopBack = Mpx.config?.rnConfig?.onStackTopBack
@@ -150,28 +148,25 @@ function createMpxNav(options: MpxNavFactorOptions) {
150
148
  : null
151
149
 
152
150
  return (
153
- // 不设置 zIndex transform 无法生效
154
- <Animated.View style={[{ position: 'relative', zIndex: 10000 }, animatedStyle]}>
155
- <View
156
- style={[
157
- styles.header,
158
- {
159
- paddingTop: safeAreaTop,
160
- backgroundColor: innerPageConfig.navigationBarBackgroundColor || '#000000'
161
- }
162
- ]}>
163
- {statusBarElement}
164
- {/* TODO: 确定 height 的有效性 */}
165
- {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
166
- {/* @ts-expect-error */}
167
- <View style={styles.headerContent} height={titleHeight}>
168
- {backElement}
169
- <Text style={[styles.title, { color: navigationBarTextStyle }]} numberOfLines={1}>
170
- {innerPageConfig.navigationBarTitleText?.trim() || ''}
171
- </Text>
172
- </View>
151
+ <View
152
+ style={[
153
+ styles.header,
154
+ {
155
+ paddingTop: safeAreaTop,
156
+ backgroundColor: innerPageConfig.navigationBarBackgroundColor || '#000000'
157
+ }
158
+ ]}>
159
+ {statusBarElement}
160
+ {/* TODO: 确定 height 的有效性 */}
161
+ {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
162
+ {/* @ts-expect-error */}
163
+ <View style={styles.headerContent} height={titleHeight}>
164
+ {backElement}
165
+ <Text style={[styles.title, { color: navigationBarTextStyle }]} numberOfLines={1}>
166
+ {innerPageConfig.navigationBarTitleText?.trim() || ''}
167
+ </Text>
173
168
  </View>
174
- </Animated.View>
169
+ </View>
175
170
  )
176
171
 
177
172
  // return createElement(
@@ -0,0 +1,8 @@
1
+ import { useContext } from 'react'
2
+ import { NavSharedContext } from './context'
3
+
4
+ export function useNavShared () {
5
+ const navSharedValue = useContext(NavSharedContext)
6
+
7
+ return [navSharedValue.customNav, navSharedValue.setCustomNav] as const
8
+ }
@@ -0,0 +1,13 @@
1
+ <script>
2
+ export default {
3
+ name: 'mpx-view',
4
+ data() {
5
+ return {}
6
+ },
7
+ props: {},
8
+ render() {
9
+ return this.$slots.default
10
+ },
11
+ methods: {}
12
+ }
13
+ </script>
@@ -0,0 +1,9 @@
1
+ <template>
2
+ <slot />
3
+ </template>
4
+ <script type="application/json">
5
+ {
6
+ "component": true,
7
+ "usingComponents": {}
8
+ }
9
+ </script>
@@ -78,7 +78,7 @@ const isBuildInWebTag = makeMap(
78
78
  'mpx-swiper,mpx-view,mpx-checkbox-group,mpx-movable-area,mpx-radio-group,' +
79
79
  'mpx-switch,mpx-web-view,mpx-checkbox,mpx-movable-view,mpx-radio,' +
80
80
  'mpx-tab-bar-container,mpx-form,mpx-navigator,mpx-rich-text,mpx-tab-bar,' +
81
- 'mpx-icon,mpx-picker-view-column,mpx-scroll-view,mpx-text'
81
+ 'mpx-icon,mpx-picker-view-column,mpx-scroll-view,mpx-text,mpx-nav-container'
82
82
  )
83
83
 
84
84
  /**
@@ -91,7 +91,7 @@ const isBuildInReactTag = makeMap(
91
91
  'mpx-movable-area,mpx-label,mpx-keyboard-avoiding-view,mpx-input,mpx-inline-text,' +
92
92
  'mpx-image,mpx-form,mpx-checkbox,mpx-checkbox-group,mpx-button,' +
93
93
  'mpx-rich-text,mpx-portal,mpx-popup,mpx-picker-view-column,mpx-picker-view,mpx-picker,' +
94
- 'mpx-icon,mpx-canvas'
94
+ 'mpx-icon,mpx-canvas,mpx-nav-container'
95
95
  )
96
96
 
97
97
  const isSpace = makeMap('ensp,emsp,nbsp')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mpxjs/webpack-plugin",
3
- "version": "2.10.6-beta.8",
3
+ "version": "2.10.6-beta.9",
4
4
  "description": "mpx compile core",
5
5
  "keywords": [
6
6
  "mpx"