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

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 (80) hide show
  1. package/lib/index.js +5 -2
  2. package/lib/runtime/components/react/context.ts +8 -3
  3. package/lib/runtime/components/react/dist/AsyncSuspense.d.ts +16 -0
  4. package/lib/runtime/components/react/dist/context.d.ts +74 -0
  5. package/lib/runtime/components/react/dist/event.config.d.ts +7 -0
  6. package/lib/runtime/components/react/dist/getInnerListeners.d.ts +7 -0
  7. package/lib/runtime/components/react/dist/mpx-button.d.ts +68 -0
  8. package/lib/runtime/components/react/dist/mpx-canvas/Bus.d.ts +23 -0
  9. package/lib/runtime/components/react/dist/mpx-canvas/CanvasGradient.d.ts +7 -0
  10. package/lib/runtime/components/react/dist/mpx-canvas/CanvasRenderingContext2D.d.ts +6 -0
  11. package/lib/runtime/components/react/dist/mpx-canvas/Image.d.ts +20 -0
  12. package/lib/runtime/components/react/dist/mpx-canvas/ImageData.d.ts +8 -0
  13. package/lib/runtime/components/react/dist/mpx-canvas/constructorsRegistry.d.ts +10 -0
  14. package/lib/runtime/components/react/dist/mpx-canvas/html.d.ts +2 -0
  15. package/lib/runtime/components/react/dist/mpx-canvas/index.d.ts +32 -0
  16. package/lib/runtime/components/react/dist/mpx-canvas/utils.d.ts +52 -0
  17. package/lib/runtime/components/react/dist/mpx-checkbox-group.d.ts +20 -0
  18. package/lib/runtime/components/react/dist/mpx-checkbox.d.ts +32 -0
  19. package/lib/runtime/components/react/dist/mpx-form.d.ts +27 -0
  20. package/lib/runtime/components/react/dist/mpx-icon/index.d.ts +18 -0
  21. package/lib/runtime/components/react/dist/mpx-image.d.ts +21 -0
  22. package/lib/runtime/components/react/dist/mpx-inline-text.d.ts +7 -0
  23. package/lib/runtime/components/react/dist/mpx-input.d.ts +49 -0
  24. package/lib/runtime/components/react/dist/mpx-input.jsx +30 -9
  25. package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.d.ts +13 -0
  26. package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +63 -28
  27. package/lib/runtime/components/react/dist/mpx-label.d.ts +20 -0
  28. package/lib/runtime/components/react/dist/mpx-movable-area.d.ts +20 -0
  29. package/lib/runtime/components/react/dist/mpx-movable-view.d.ts +61 -0
  30. package/lib/runtime/components/react/dist/mpx-navigator.d.ts +9 -0
  31. package/lib/runtime/components/react/dist/mpx-picker/date.d.ts +6 -0
  32. package/lib/runtime/components/react/dist/mpx-picker/dateData.d.ts +7 -0
  33. package/lib/runtime/components/react/dist/mpx-picker/index.d.ts +6 -0
  34. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.d.ts +6 -0
  35. package/lib/runtime/components/react/dist/mpx-picker/region.d.ts +6 -0
  36. package/lib/runtime/components/react/dist/mpx-picker/regionData.d.ts +2 -0
  37. package/lib/runtime/components/react/dist/mpx-picker/selector.d.ts +6 -0
  38. package/lib/runtime/components/react/dist/mpx-picker/time.d.ts +6 -0
  39. package/lib/runtime/components/react/dist/mpx-picker/type.d.ts +106 -0
  40. package/lib/runtime/components/react/dist/mpx-picker-view/index.d.ts +31 -0
  41. package/lib/runtime/components/react/dist/mpx-picker-view/pickerVIewContext.d.ts +8 -0
  42. package/lib/runtime/components/react/dist/mpx-picker-view-column/index.d.ts +22 -0
  43. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItem.d.ts +14 -0
  44. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewFaces.d.ts +16 -0
  45. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewIndicator.d.ts +12 -0
  46. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewMask.d.ts +11 -0
  47. package/lib/runtime/components/react/dist/mpx-popup/index.d.ts +22 -0
  48. package/lib/runtime/components/react/dist/mpx-popup/popupBase.d.ts +16 -0
  49. package/lib/runtime/components/react/dist/mpx-portal/index.d.ts +15 -0
  50. package/lib/runtime/components/react/dist/mpx-portal/portal-host.d.ts +29 -0
  51. package/lib/runtime/components/react/dist/mpx-portal/portal-manager.d.ts +9 -0
  52. package/lib/runtime/components/react/dist/mpx-radio-group.d.ts +20 -0
  53. package/lib/runtime/components/react/dist/mpx-radio.d.ts +26 -0
  54. package/lib/runtime/components/react/dist/mpx-rich-text/html.d.ts +1 -0
  55. package/lib/runtime/components/react/dist/mpx-rich-text/index.d.ts +24 -0
  56. package/lib/runtime/components/react/dist/mpx-root-portal.d.ts +14 -0
  57. package/lib/runtime/components/react/dist/mpx-scroll-view.d.ts +53 -0
  58. package/lib/runtime/components/react/dist/mpx-simple-text.d.ts +7 -0
  59. package/lib/runtime/components/react/dist/mpx-simple-view.d.ts +7 -0
  60. package/lib/runtime/components/react/dist/mpx-sticky-header.d.ts +17 -0
  61. package/lib/runtime/components/react/dist/mpx-sticky-section.d.ts +15 -0
  62. package/lib/runtime/components/react/dist/mpx-swiper-item.d.ts +18 -0
  63. package/lib/runtime/components/react/dist/mpx-swiper.d.ts +53 -0
  64. package/lib/runtime/components/react/dist/mpx-switch.d.ts +26 -0
  65. package/lib/runtime/components/react/dist/mpx-text.d.ts +21 -0
  66. package/lib/runtime/components/react/dist/mpx-textarea.d.ts +7 -0
  67. package/lib/runtime/components/react/dist/mpx-video.d.ts +101 -0
  68. package/lib/runtime/components/react/dist/mpx-view.d.ts +34 -0
  69. package/lib/runtime/components/react/dist/mpx-web-view.d.ts +22 -0
  70. package/lib/runtime/components/react/dist/nav.d.ts +11 -0
  71. package/lib/runtime/components/react/dist/nav.jsx +189 -0
  72. package/lib/runtime/components/react/dist/parser.d.ts +39 -0
  73. package/lib/runtime/components/react/dist/useAnimationHooks.d.ts +32 -0
  74. package/lib/runtime/components/react/dist/useNodesRef.d.ts +11 -0
  75. package/lib/runtime/components/react/dist/utils.d.ts +121 -0
  76. package/lib/runtime/components/react/mpx-input.tsx +36 -16
  77. package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +68 -28
  78. package/lib/runtime/components/react/nav.tsx +219 -0
  79. package/lib/runtime/components/react/types/common.d.ts +19 -0
  80. package/package.json +1 -1
@@ -0,0 +1,189 @@
1
+ /* eslint-disable space-before-function-paren */
2
+ import { createElement, useState, useMemo, memo } from 'react';
3
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
4
+ import { StatusBar, processColor, TouchableWithoutFeedback, Image, View, StyleSheet, Text } from 'react-native';
5
+ import Animated, { useSharedValue, useAnimatedStyle, withTiming, Easing } from 'react-native-reanimated';
6
+ function convertToHex(color) {
7
+ try {
8
+ const intColor = processColor(color);
9
+ if (intColor === null || intColor === undefined) {
10
+ return null;
11
+ }
12
+ // 将32位整数颜色值转换为RGBA
13
+ const r = (intColor >> 16) & 255;
14
+ const g = (intColor >> 8) & 255;
15
+ const b = intColor & 255;
16
+ // 转换为十六进制
17
+ const hexR = r.toString(16).padStart(2, '0');
18
+ const hexG = g.toString(16).padStart(2, '0');
19
+ const hexB = b.toString(16).padStart(2, '0');
20
+ return `#${hexR}${hexG}${hexB}`;
21
+ }
22
+ catch (error) {
23
+ return null;
24
+ }
25
+ }
26
+ const titleHeight = 44;
27
+ export function useInnerHeaderHeight(pageConfig) {
28
+ const safeArea = useSafeAreaInsets();
29
+ if (pageConfig.navigationStyle === 'custom') {
30
+ return 0;
31
+ }
32
+ else {
33
+ const safeAreaTop = safeArea?.top || 0;
34
+ const headerHeight = safeAreaTop + titleHeight;
35
+ return headerHeight;
36
+ }
37
+ }
38
+ const styles = StyleSheet.create({
39
+ header: {
40
+ elevation: 3
41
+ },
42
+ headerContent: {
43
+ flexDirection: 'row',
44
+ alignItems: 'center',
45
+ justifyContent: 'center'
46
+ },
47
+ backButton: {
48
+ position: 'absolute',
49
+ height: '100%',
50
+ width: 40,
51
+ left: 0,
52
+ top: 0,
53
+ alignItems: 'center',
54
+ justifyContent: 'center'
55
+ },
56
+ backButtonImage: {
57
+ width: 22,
58
+ height: 22
59
+ },
60
+ title: {
61
+ fontSize: 17,
62
+ fontWeight: 600,
63
+ width: '60%',
64
+ textAlign: 'center'
65
+ }
66
+ });
67
+ const NavColor = {
68
+ White: '#ffffff',
69
+ Black: '#000000'
70
+ };
71
+ // navigationBarTextStyle 只支持黑白 'white'/'black
72
+ const validBarTextStyle = (textStyle) => {
73
+ const textStyleColor = convertToHex(textStyle);
74
+ if (textStyle && textStyleColor && [NavColor.White, NavColor.Black].includes(textStyleColor)) {
75
+ return textStyleColor;
76
+ }
77
+ else {
78
+ return NavColor.White;
79
+ }
80
+ };
81
+ const BACK_ICON = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAABICAYAAACqT5alAAAA2UlEQVR4nO3bMQrCUBRE0Yla6AYEN2nnBrTL+izcitW3MRDkEUWSvPzJvfCqgMwhZbAppWhNbbIHzB1g9wATERFRVyvpkj1irlpJ5X326D7WHh1hbdFD2CLpLmmftm7kfsEe09aNHFiBrT+wAlt/YAW2/sAKbP2BFdj6Ayuwy+ufz6XPL893krZ//O6iu2n4LT8kndLWTRTo4EC7BDo40C6BDg60S6CDA+0S6OBAuwQ6uNWiD2nrJmoIfU7cNWkR2hbb1UfbY7uuWhGWiIg+a/iHuHmA3QPs3gu4JW9Gan+OJAAAAABJRU5ErkJggg==';
82
+ function createMpxNav(options) {
83
+ const { Mpx } = options;
84
+ const innerNav = memo(({ pageConfig, navigation }) => {
85
+ const [innerPageConfig, setPageConfig] = useState(pageConfig || {});
86
+ const translateY = useSharedValue(0);
87
+ const safeAreaTop = useSafeAreaInsets()?.top || 0;
88
+ const animatedStyle = useAnimatedStyle(() => ({
89
+ transform: [{ translateY: translateY.value }]
90
+ }));
91
+ 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);
96
+ };
97
+ const isCustom = innerPageConfig.navigationStyle === 'custom';
98
+ const navigationBarTextStyle = useMemo(() => validBarTextStyle(innerPageConfig.navigationBarTextStyle), [innerPageConfig.navigationBarTextStyle]);
99
+ // 状态栏的颜色
100
+ const statusBarElement = (<StatusBar translucent backgroundColor='transparent' barStyle={navigationBarTextStyle === NavColor.White ? 'light-content' : 'dark-content'}></StatusBar>);
101
+ createElement(StatusBar, {
102
+ translucent: true,
103
+ backgroundColor: 'transparent',
104
+ barStyle: navigationBarTextStyle === NavColor.White ? 'light-content' : 'dark-content' // 'default'/'light-content'/'dark-content'
105
+ });
106
+ if (isCustom)
107
+ return statusBarElement;
108
+ // 假设是栈导航,获取栈的长度
109
+ const stackLength = navigation.getState()?.routes?.length;
110
+ const onStackTopBack = Mpx.config?.rnConfig?.onStackTopBack;
111
+ const isHandleStackTopBack = typeof onStackTopBack === 'function';
112
+ // 回退按钮与图标
113
+ // prettier-ignore
114
+ const backElement = stackLength > 1 || isHandleStackTopBack
115
+ ? (<TouchableWithoutFeedback onPress={() => {
116
+ if (stackLength <= 1 && isHandleStackTopBack) {
117
+ onStackTopBack();
118
+ return;
119
+ }
120
+ navigation.goBack();
121
+ }}>
122
+ <View style={[styles.backButton]}>
123
+ <Image style={[styles.backButtonImage, { tintColor: navigationBarTextStyle }]} source={{ uri: BACK_ICON }}></Image>
124
+ </View>
125
+ </TouchableWithoutFeedback>)
126
+ : null;
127
+ return (
128
+ // 不设置 zIndex transform 无法生效
129
+ <Animated.View style={[{ position: 'relative', zIndex: 10000 }, animatedStyle]}>
130
+ <View style={[
131
+ styles.header,
132
+ {
133
+ paddingTop: safeAreaTop,
134
+ backgroundColor: innerPageConfig.navigationBarBackgroundColor || '#000000'
135
+ }
136
+ ]}>
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>
147
+ </View>
148
+ </Animated.View>);
149
+ // return createElement(
150
+ // Animated.View,
151
+ // {
152
+ // style: [animatedStyle]
153
+ // },
154
+ // createElement(
155
+ // View,
156
+ // {
157
+ // style: [
158
+ // styles.header,
159
+ // {
160
+ // paddingTop: safeAreaTop,
161
+ // backgroundColor: innerPageConfig.navigationBarBackgroundColor || '#000000'
162
+ // },
163
+ // innerPageConfig.navStyle ?? {}
164
+ // ]
165
+ // },
166
+ // statusBarElement,
167
+ // createElement(
168
+ // View,
169
+ // {
170
+ // style: styles.headerContent,
171
+ // height: titleHeight
172
+ // },
173
+ // backElement,
174
+ // createElement(
175
+ // Text,
176
+ // {
177
+ // style: [styles.title, { color: navigationBarTextStyle }],
178
+ // numberOfLines: 1
179
+ // },
180
+ // innerPageConfig.navigationBarTitleText?.trim() || ''
181
+ // )
182
+ // )
183
+ // )
184
+ // )
185
+ });
186
+ innerNav.displayName = 'MpxNav';
187
+ return innerNav;
188
+ }
189
+ export default createMpxNav;
@@ -0,0 +1,39 @@
1
+ interface Token {
2
+ type: string;
3
+ value: string | number;
4
+ }
5
+ interface ExpressionNode {
6
+ type: 'NUMBER';
7
+ value: number;
8
+ }
9
+ export declare class ExpressionParser {
10
+ private tokens;
11
+ private formatter;
12
+ private functions;
13
+ private current;
14
+ constructor(input: string, formatter?: (val: string) => number, functions?: {
15
+ [key: string]: (...args: number[]) => number;
16
+ });
17
+ tokenize(input: string): Token[];
18
+ parse(): ExpressionNode;
19
+ private expression;
20
+ private term;
21
+ private factor;
22
+ private parseArguments;
23
+ private applyOperator;
24
+ private applyFunction;
25
+ }
26
+ interface FuncInfo {
27
+ start: number;
28
+ end: number;
29
+ args: string[];
30
+ }
31
+ export declare function parseFunc(str: string, funcName: string): FuncInfo[];
32
+ export declare class ReplaceSource {
33
+ private _source;
34
+ private _replacements;
35
+ constructor(source: string);
36
+ replace(start: number, end: number, content: string): void;
37
+ source(): string;
38
+ }
39
+ export {};
@@ -0,0 +1,32 @@
1
+ import type { MutableRefObject } from 'react';
2
+ import type { NativeSyntheticEvent } from 'react-native';
3
+ import { ExtendedViewStyle } from './types/common';
4
+ import type { _ViewProps } from './mpx-view';
5
+ type AnimatedOption = {
6
+ duration: number;
7
+ delay: number;
8
+ useNativeDriver: boolean;
9
+ timingFunction: 'linear' | 'ease' | 'ease-in' | 'ease-in-out' | 'ease-out';
10
+ transformOrigin: string;
11
+ };
12
+ export type AnimationStepItem = {
13
+ animatedOption: AnimatedOption;
14
+ rules: Map<string, number | string>;
15
+ transform: Map<string, number>;
16
+ };
17
+ export type AnimationProp = {
18
+ id: number;
19
+ actions: AnimationStepItem[];
20
+ };
21
+ export default function useAnimationHooks<T, P>(props: _ViewProps & {
22
+ enableAnimation?: boolean;
23
+ layoutRef: MutableRefObject<any>;
24
+ transitionend?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void;
25
+ }): {
26
+ enableStyleAnimation: boolean;
27
+ animationStyle?: undefined;
28
+ } | {
29
+ enableStyleAnimation: true;
30
+ animationStyle: ExtendedViewStyle;
31
+ };
32
+ export {};
@@ -0,0 +1,11 @@
1
+ import { RefObject, ForwardedRef } from 'react';
2
+ type Obj = Record<string, any>;
3
+ export type HandlerRef<T, P> = {
4
+ getNodeInstance(): {
5
+ props: RefObject<P>;
6
+ nodeRef: RefObject<T>;
7
+ instance: Obj;
8
+ };
9
+ };
10
+ export default function useNodesRef<T, P>(props: P, ref: ForwardedRef<HandlerRef<T, P>>, nodeRef: RefObject<T>, instance?: Obj): void;
11
+ export {};
@@ -0,0 +1,121 @@
1
+ import { ReactNode, ReactElement, Dispatch, SetStateAction } from 'react';
2
+ import { LayoutChangeEvent, TextStyle, ImageProps } from 'react-native';
3
+ import { FastImageProps } from '@d11/react-native-fast-image';
4
+ import type { AnyFunc } from './types/common';
5
+ export declare const TEXT_STYLE_REGEX: RegExp;
6
+ export declare const PERCENT_REGEX: RegExp;
7
+ export declare const URL_REGEX: RegExp;
8
+ export declare const SVG_REGEXP: RegExp;
9
+ export declare const BACKGROUND_REGEX: RegExp;
10
+ export declare const TEXT_PROPS_REGEX: RegExp;
11
+ export declare const DEFAULT_FONT_SIZE = 16;
12
+ export declare const HIDDEN_STYLE: {
13
+ opacity: number;
14
+ };
15
+ export declare const isIOS: boolean;
16
+ export declare const isAndroid: boolean;
17
+ export declare const isHarmony: boolean;
18
+ export declare function useNavigation(): Record<string, any> | undefined;
19
+ export declare function omit<T, K extends string>(obj: T, fields: K[]): Omit<T, K>;
20
+ /**
21
+ * 用法等同于 useEffect,但是会忽略首次执行,只在依赖更新时执行
22
+ */
23
+ export declare const useUpdateEffect: (effect: any, deps: any) => void;
24
+ export declare const parseUrl: (cssUrl?: string) => string | undefined;
25
+ export declare const getRestProps: (transferProps?: any, originProps?: any, deletePropsKey?: any) => any;
26
+ export declare function isText(ele: ReactNode): ele is ReactElement;
27
+ export declare function every(children: ReactNode, callback: (children: ReactNode) => boolean): boolean;
28
+ type GroupData<T> = Record<string, Partial<T>>;
29
+ export declare function groupBy<T extends Record<string, any>>(obj: T, callback: (key: string, val: T[keyof T]) => string, group?: GroupData<T>): GroupData<T>;
30
+ export declare function splitStyle<T extends Record<string, any>>(styleObj: T): {
31
+ textStyle?: Partial<T>;
32
+ backgroundStyle?: Partial<T>;
33
+ innerStyle?: Partial<T>;
34
+ };
35
+ interface TransformStyleConfig {
36
+ enableVar?: boolean;
37
+ externalVarContext?: Record<string, any>;
38
+ parentFontSize?: number;
39
+ parentWidth?: number;
40
+ parentHeight?: number;
41
+ }
42
+ export declare function useTransformStyle(styleObj: Record<string, any> | undefined, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }: TransformStyleConfig): {
43
+ hasVarDec: boolean;
44
+ varContextRef: import("react").MutableRefObject<{}>;
45
+ setWidth: Dispatch<SetStateAction<number>>;
46
+ setHeight: Dispatch<SetStateAction<number>>;
47
+ normalStyle: Record<string, any>;
48
+ hasSelfPercent: boolean;
49
+ hasPositionFixed: boolean;
50
+ };
51
+ export interface VisitorArg {
52
+ target: Record<string, any>;
53
+ key: string;
54
+ value: any;
55
+ keyPath: Array<string>;
56
+ }
57
+ export declare function traverseStyle(styleObj: Record<string, any>, visitors: Array<(arg: VisitorArg) => void>): void;
58
+ export declare function setStyle(styleObj: Record<string, any>, keyPath: Array<string>, setter: (arg: VisitorArg) => void): void;
59
+ export declare function splitProps<T extends Record<string, any>>(props: T): {
60
+ textProps?: Partial<T>;
61
+ innerProps?: Partial<T>;
62
+ };
63
+ interface LayoutConfig {
64
+ props: Record<string, any>;
65
+ hasSelfPercent: boolean;
66
+ setWidth?: Dispatch<SetStateAction<number>>;
67
+ setHeight?: Dispatch<SetStateAction<number>>;
68
+ onLayout?: (event?: LayoutChangeEvent) => void;
69
+ nodeRef: React.RefObject<any>;
70
+ }
71
+ export declare const useLayout: ({ props, hasSelfPercent, setWidth, setHeight, onLayout, nodeRef }: LayoutConfig) => {
72
+ layoutRef: import("react").MutableRefObject<{}>;
73
+ layoutStyle: {};
74
+ layoutProps: Record<string, any>;
75
+ };
76
+ export interface WrapChildrenConfig {
77
+ hasVarDec: boolean;
78
+ varContext?: Record<string, any>;
79
+ textStyle?: TextStyle;
80
+ textProps?: Record<string, any>;
81
+ }
82
+ export declare function wrapChildren(props: Record<string, any> | undefined, { hasVarDec, varContext, textStyle, textProps }: WrapChildrenConfig): any;
83
+ export declare const debounce: <T extends AnyFunc>(func: T, delay: number) => ((...args: Parameters<T>) => void) & {
84
+ clear: () => void;
85
+ };
86
+ export declare const useDebounceCallback: <T extends AnyFunc>(func: T, delay: number) => ((...args: Parameters<T>) => void) & {
87
+ clear: () => void;
88
+ };
89
+ export declare const useStableCallback: <T extends AnyFunc | null | undefined>(callback: T) => T extends AnyFunc ? T : () => void;
90
+ export declare function usePrevious<T>(value: T): T | undefined;
91
+ export interface GestureHandler {
92
+ nodeRefs?: Array<{
93
+ getNodeInstance: () => {
94
+ nodeRef: unknown;
95
+ };
96
+ }>;
97
+ current?: unknown;
98
+ }
99
+ export declare function flatGesture(gestures?: Array<GestureHandler>): any[];
100
+ export declare const extendObject: {
101
+ <T extends {}, U>(target: T, source: U): T & U;
102
+ <T_1 extends {}, U_1, V>(target: T_1, source1: U_1, source2: V): T_1 & U_1 & V;
103
+ <T_2 extends {}, U_2, V_1, W>(target: T_2, source1: U_2, source2: V_1, source3: W): T_2 & U_2 & V_1 & W;
104
+ (target: object, ...sources: any[]): any;
105
+ };
106
+ export declare function getCurrentPage(pageId: number | null | undefined): any;
107
+ export declare function renderImage(imageProps: ImageProps | FastImageProps, enableFastImage?: boolean): ReactElement<ImageProps | FastImageProps, string | import("react").JSXElementConstructor<any>>;
108
+ export declare function pickStyle(styleObj: Record<string, any> | undefined, pickedKeys: Array<string>, callback?: (key: string, val: number | string) => number | string): Record<string, any>;
109
+ export declare function useHover({ enableHover, hoverStartTime, hoverStayTime, disabled }: {
110
+ enableHover: boolean;
111
+ hoverStartTime: number;
112
+ hoverStayTime: number;
113
+ disabled?: boolean;
114
+ }): {
115
+ isHover: boolean;
116
+ gesture?: undefined;
117
+ } | {
118
+ isHover: boolean;
119
+ gesture: import("react-native-gesture-handler/lib/typescript/handlers/gestures/panGesture").PanGesture;
120
+ };
121
+ export {};
@@ -280,8 +280,8 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
280
280
  }
281
281
 
282
282
  const setKeyboardAvoidContext = () => {
283
- if (adjustPosition && keyboardAvoid) {
284
- keyboardAvoid.current = { cursorSpacing, ref: nodeRef }
283
+ if (keyboardAvoid) {
284
+ keyboardAvoid.current = { cursorSpacing, ref: nodeRef, adjustPosition, blurCallbacks: [] }
285
285
  }
286
286
  }
287
287
 
@@ -295,23 +295,42 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
295
295
  }
296
296
 
297
297
  const onFocus = (evt: NativeSyntheticEvent<TextInputFocusEventData>) => {
298
- setKeyboardAvoidContext()
299
- bindfocus && bindfocus(
300
- getCustomEvent(
301
- 'focus',
302
- evt,
303
- {
304
- detail: {
305
- value: tmpValue.current || ''
306
- },
307
- layoutRef
308
- },
309
- props
310
- )
311
- )
298
+ if (!keyboardAvoid?.current) {
299
+ setKeyboardAvoidContext()
300
+ }
301
+ if (bindfocus && keyboardAvoid?.current) {
302
+ const focusAction = () => {
303
+ bindfocus(
304
+ getCustomEvent(
305
+ 'focus',
306
+ evt,
307
+ {
308
+ detail: {
309
+ value: tmpValue.current || '',
310
+ height: keyboardAvoid.current?.keyboardHeight
311
+ },
312
+ layoutRef
313
+ },
314
+ props
315
+ )
316
+ )
317
+ if (keyboardAvoid.current?.onKeyboardShow) {
318
+ keyboardAvoid.current.onKeyboardShow = undefined
319
+ }
320
+ }
321
+ if (keyboardAvoid.current.keyboardHeight) {
322
+ // iOS: keyboard 获取高度时机 keyboardWillShow 在 input focus 之前,可以立即执行
323
+ focusAction()
324
+ } else {
325
+ // Android,Harmony: keyboard 获取高度时机 keyboardDidShow 在 input focus 之后,需要延迟回调
326
+ evt.persist()
327
+ keyboardAvoid.current.onKeyboardShow = focusAction
328
+ }
329
+ }
312
330
  }
313
331
 
314
332
  const onBlur = (evt: NativeSyntheticEvent<TextInputFocusEventData>) => {
333
+ keyboardAvoid?.current?.blurCallbacks.forEach(fn => fn())
315
334
  bindblur && bindblur(
316
335
  getCustomEvent(
317
336
  'blur',
@@ -456,6 +475,7 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
456
475
  multiline: !!multiline,
457
476
  onTouchStart,
458
477
  onTouchEnd,
478
+ onTouchMove: onTouchEnd,
459
479
  onFocus,
460
480
  onBlur,
461
481
  onChange,
@@ -1,6 +1,7 @@
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'
4
5
  import { KeyboardAvoidContext } from './context'
5
6
  import { isIOS } from './utils'
6
7
 
@@ -8,9 +9,10 @@ type KeyboardAvoidViewProps = {
8
9
  children?: ReactNode
9
10
  style?: ViewStyle
10
11
  contentContainerStyle?: ViewStyle
12
+ navigation?: any
11
13
  }
12
14
 
13
- const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: KeyboardAvoidViewProps) => {
15
+ const KeyboardAvoidingView = ({ children, style, contentContainerStyle, navigation }: KeyboardAvoidViewProps) => {
14
16
  const duration = isIOS ? 250 : 300
15
17
  const easing = isIOS ? Easing.inOut(Easing.ease) : Easing.out(Easing.quad)
16
18
 
@@ -25,7 +27,17 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
25
27
 
26
28
  const resetKeyboard = () => {
27
29
  if (keyboardAvoid?.current) {
30
+ const inputRef = keyboardAvoid.current.ref?.current
31
+ if (inputRef && inputRef.isFocused()) {
32
+ // 修复 Android 点击键盘收起按钮时当前 input 没触发失焦的问题
33
+ inputRef.blur()
34
+ }
28
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
+ })
29
41
  }
30
42
  offset.value = withTiming(0, { duration, easing })
31
43
  basic.value = 'auto'
@@ -45,21 +57,25 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
45
57
  Keyboard.addListener('keyboardWillShow', (evt: any) => {
46
58
  if (!keyboardAvoid?.current) return
47
59
  const { endCoordinates } = evt
48
- const { ref, cursorSpacing = 0 } = keyboardAvoid.current
49
- setTimeout(() => {
50
- ref?.current?.measure((x: number, y: number, width: number, height: number, pageX: number, pageY: number) => {
51
- const aboveOffset = offset.value + pageY + height - endCoordinates.screenY
52
- const aboveValue = -aboveOffset >= cursorSpacing ? 0 : aboveOffset + cursorSpacing
53
- const belowValue = Math.min(endCoordinates.height, aboveOffset + cursorSpacing)
54
- const value = aboveOffset > 0 ? belowValue : aboveValue
55
- offset.value = withTiming(value, { duration, easing }, (finished) => {
56
- if (finished) {
57
- // Set flexBasic after animation to trigger re-layout and reset layout information
58
- basic.value = '99.99%'
59
- }
60
+ const { ref, cursorSpacing = 0, adjustPosition, onKeyboardShow } = keyboardAvoid.current
61
+ keyboardAvoid.current.keyboardHeight = endCoordinates.height
62
+ onKeyboardShow?.()
63
+ if (adjustPosition) {
64
+ setTimeout(() => {
65
+ ref?.current?.measure((x: number, y: number, width: number, height: number, pageX: number, pageY: number) => {
66
+ const aboveOffset = offset.value + pageY + height - endCoordinates.screenY
67
+ const aboveValue = -aboveOffset >= cursorSpacing ? 0 : aboveOffset + cursorSpacing
68
+ const belowValue = Math.min(endCoordinates.height, aboveOffset + cursorSpacing)
69
+ const value = aboveOffset > 0 ? belowValue : aboveValue
70
+ offset.value = withTiming(value, { duration, easing }, (finished) => {
71
+ if (finished) {
72
+ // Set flexBasic after animation to trigger re-layout and reset layout information
73
+ basic.value = '99.99%'
74
+ }
75
+ })
60
76
  })
61
77
  })
62
- })
78
+ }
63
79
  }),
64
80
  Keyboard.addListener('keyboardWillHide', resetKeyboard)
65
81
  ]
@@ -68,20 +84,44 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
68
84
  Keyboard.addListener('keyboardDidShow', (evt: any) => {
69
85
  if (!keyboardAvoid?.current) return
70
86
  const { endCoordinates } = evt
71
- const { ref, cursorSpacing = 0 } = keyboardAvoid.current
72
- ref?.current?.measure((x: number, y: number, width: number, height: number, pageX: number, pageY: number) => {
73
- const aboveOffset = pageY + height - endCoordinates.screenY
74
- const belowOffset = endCoordinates.height - aboveOffset
75
- const aboveValue = -aboveOffset >= cursorSpacing ? 0 : aboveOffset + cursorSpacing
76
- const belowValue = Math.min(belowOffset, cursorSpacing)
77
- const value = aboveOffset > 0 ? belowValue : aboveValue
78
- offset.value = withTiming(value, { duration, easing }, (finished) => {
79
- if (finished) {
80
- // Set flexBasic after animation to trigger re-layout and reset layout information
81
- basic.value = '99.99%'
82
- }
87
+ const { ref, cursorSpacing = 0, adjustPosition, onKeyboardShow } = keyboardAvoid.current
88
+ // android 上键盘消失只能使用 keyboardDidHide 事件,对于需要和键盘一起改变位置的 nav 来说
89
+ // keyboardDidHide 是比较晚的,从动画上看也并不同步,因此采用比较早的blur
90
+ keyboardAvoid.current.blurCallbacks.push(resetKeyboard)
91
+ keyboardAvoid.current.keyboardHeight = endCoordinates.height
92
+ 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
105
+
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) => {
118
+ if (finished) {
119
+ // Set flexBasic after animation to trigger re-layout and reset layout information
120
+ basic.value = '99.99%'
121
+ }
122
+ })
83
123
  })
84
- })
124
+ }
85
125
  }),
86
126
  Keyboard.addListener('keyboardDidHide', resetKeyboard)
87
127
  ]
@@ -93,7 +133,7 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
93
133
  }, [keyboardAvoid])
94
134
 
95
135
  return (
96
- <View style={style} onTouchEnd={onTouchEnd}>
136
+ <View style={style} onTouchEnd={onTouchEnd} onTouchMove={onTouchEnd}>
97
137
  <Animated.View
98
138
  style={[
99
139
  contentContainerStyle,