@mpxjs/webpack-plugin 2.10.4-beta.19 → 2.10.4-beta.19-input

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 (35) hide show
  1. package/lib/runtime/components/react/dist/getInnerListeners.js +36 -22
  2. package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +145 -0
  3. package/lib/runtime/components/react/dist/mpx-button.jsx +7 -2
  4. package/lib/runtime/components/react/dist/mpx-canvas/Image.js +2 -4
  5. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +20 -17
  6. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +7 -2
  7. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +7 -2
  8. package/lib/runtime/components/react/dist/mpx-icon/index.jsx +7 -2
  9. package/lib/runtime/components/react/dist/mpx-image.jsx +33 -20
  10. package/lib/runtime/components/react/dist/mpx-input.jsx +7 -2
  11. package/lib/runtime/components/react/dist/mpx-label.jsx +7 -2
  12. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +8 -3
  13. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +205 -79
  14. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +11 -13
  15. package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +8 -7
  16. package/lib/runtime/components/react/dist/mpx-picker-view-column/index.jsx +29 -11
  17. package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +3 -5
  18. package/lib/runtime/components/react/dist/mpx-progress.jsx +163 -0
  19. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +9 -2
  20. package/lib/runtime/components/react/dist/mpx-radio.jsx +7 -2
  21. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +10 -2
  22. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +104 -51
  23. package/lib/runtime/components/react/dist/mpx-slider.jsx +321 -0
  24. package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +3 -1
  25. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +11 -9
  26. package/lib/runtime/components/react/dist/mpx-swiper.jsx +203 -141
  27. package/lib/runtime/components/react/dist/mpx-switch.jsx +7 -2
  28. package/lib/runtime/components/react/dist/mpx-text.jsx +7 -2
  29. package/lib/runtime/components/react/dist/mpx-video.jsx +7 -2
  30. package/lib/runtime/components/react/dist/mpx-view.jsx +28 -26
  31. package/lib/runtime/components/react/dist/mpx-web-view.jsx +34 -29
  32. package/lib/runtime/components/react/dist/useAnimationHooks.js +12 -89
  33. package/lib/runtime/components/react/dist/utils.jsx +199 -114
  34. package/lib/runtime/components/react/mpx-input.tsx +6 -6
  35. package/package.json +1 -1
@@ -3,12 +3,13 @@ import { collectDataset } from '@mpxjs/utils';
3
3
  import { omit, extendObject, useNavigation } from './utils';
4
4
  import eventConfigMap from './event.config';
5
5
  const globalEventState = {
6
- needPress: true
6
+ needPress: true,
7
+ identifier: null
7
8
  };
8
9
  const getTouchEvent = (type, event, config) => {
9
10
  const { navigation, propsRef, layoutRef } = config;
10
11
  const props = propsRef.current;
11
- const { y: navigationY = 0 } = navigation?.layout || {};
12
+ const { top: navigationY = 0 } = navigation?.layout || {};
12
13
  const nativeEvent = event.nativeEvent;
13
14
  const { timestamp, pageX, pageY, touches, changedTouches } = nativeEvent;
14
15
  const { id } = props;
@@ -94,36 +95,48 @@ function checkIsNeedPress(e, type, ref) {
94
95
  ref.current.startTimer[type] = null;
95
96
  }
96
97
  }
98
+ function shouldHandleTapEvent(e, eventConfig) {
99
+ const { identifier } = e.nativeEvent.changedTouches[0];
100
+ return eventConfig.tap && globalEventState.identifier === identifier;
101
+ }
97
102
  function handleTouchstart(e, type, eventConfig) {
98
- // 阻止事件被释放放回对象池,导致对象复用 _stoppedEventTypes 状态被保留
99
103
  e.persist();
100
104
  const { innerRef } = eventConfig;
101
- globalEventState.needPress = true;
102
- innerRef.current.mpxPressInfo.detail = {
103
- x: e.nativeEvent.changedTouches[0].pageX,
104
- y: e.nativeEvent.changedTouches[0].pageY
105
- };
105
+ const touch = e.nativeEvent.changedTouches[0];
106
+ const { identifier } = touch;
107
+ const isSingle = e.nativeEvent.touches.length <= 1;
108
+ if (isSingle) {
109
+ // 仅在 touchstart 记录第一个单指触摸点
110
+ globalEventState.identifier = identifier;
111
+ globalEventState.needPress = true;
112
+ innerRef.current.mpxPressInfo.detail = {
113
+ x: touch.pageX,
114
+ y: touch.pageY
115
+ };
116
+ }
106
117
  handleEmitEvent('touchstart', e, type, eventConfig);
107
118
  if (eventConfig.longpress) {
108
- if (e._stoppedEventTypes?.has('longpress')) {
109
- return;
110
- }
111
- if (eventConfig.longpress.hasCatch) {
112
- e._stoppedEventTypes = e._stoppedEventTypes || new Set();
113
- e._stoppedEventTypes.add('longpress');
119
+ // 只有单指触摸时才启动长按定时器
120
+ if (isSingle) {
121
+ if (e._stoppedEventTypes?.has('longpress')) {
122
+ return;
123
+ }
124
+ if (eventConfig.longpress.hasCatch) {
125
+ e._stoppedEventTypes = e._stoppedEventTypes || new Set();
126
+ e._stoppedEventTypes.add('longpress');
127
+ }
128
+ innerRef.current.startTimer[type] && clearTimeout(innerRef.current.startTimer[type]);
129
+ innerRef.current.startTimer[type] = setTimeout(() => {
130
+ globalEventState.needPress = false;
131
+ handleEmitEvent('longpress', e, type, eventConfig);
132
+ }, 350);
114
133
  }
115
- innerRef.current.startTimer[type] && clearTimeout(innerRef.current.startTimer[type]);
116
- innerRef.current.startTimer[type] = setTimeout(() => {
117
- // 只要触发过longpress, 全局就不再触发tap
118
- globalEventState.needPress = false;
119
- handleEmitEvent('longpress', e, type, eventConfig);
120
- }, 350);
121
134
  }
122
135
  }
123
136
  function handleTouchmove(e, type, eventConfig) {
124
137
  const { innerRef } = eventConfig;
125
138
  handleEmitEvent('touchmove', e, type, eventConfig);
126
- if (eventConfig.tap) {
139
+ if (shouldHandleTapEvent(e, eventConfig)) {
127
140
  checkIsNeedPress(e, type, innerRef);
128
141
  }
129
142
  }
@@ -131,7 +144,8 @@ function handleTouchend(e, type, eventConfig) {
131
144
  const { innerRef, disableTap } = eventConfig;
132
145
  handleEmitEvent('touchend', e, type, eventConfig);
133
146
  innerRef.current.startTimer[type] && clearTimeout(innerRef.current.startTimer[type]);
134
- if (eventConfig.tap) {
147
+ // 只有单指触摸结束时才触发 tap
148
+ if (shouldHandleTapEvent(e, eventConfig)) {
135
149
  checkIsNeedPress(e, type, innerRef);
136
150
  if (!globalEventState.needPress || (type === 'bubble' && disableTap) || e._stoppedEventTypes?.has('tap')) {
137
151
  return;
@@ -0,0 +1,145 @@
1
+ import { useState, useEffect, useCallback, useRef, createElement } from 'react';
2
+ import { View, Image, StyleSheet, Text, TouchableOpacity } from 'react-native';
3
+ import FastImage from '@d11/react-native-fast-image';
4
+ const asyncChunkMap = new Map();
5
+ const styles = StyleSheet.create({
6
+ container: {
7
+ flex: 1,
8
+ padding: 20,
9
+ backgroundColor: '#fff'
10
+ },
11
+ loadingImage: {
12
+ width: 100,
13
+ height: 100,
14
+ marginTop: 220,
15
+ alignSelf: 'center'
16
+ },
17
+ buttonText: {
18
+ color: '#fff',
19
+ fontSize: 16,
20
+ fontWeight: '500',
21
+ textAlign: 'center'
22
+ },
23
+ errorImage: {
24
+ marginTop: 80,
25
+ width: 220,
26
+ aspectRatio: 1,
27
+ alignSelf: 'center'
28
+ },
29
+ errorText: {
30
+ fontSize: 16,
31
+ textAlign: 'center',
32
+ color: '#333',
33
+ marginBottom: 20
34
+ },
35
+ retryButton: {
36
+ position: 'absolute',
37
+ bottom: 54,
38
+ left: 20,
39
+ right: 20,
40
+ backgroundColor: '#fff',
41
+ paddingVertical: 15,
42
+ borderRadius: 30,
43
+ marginTop: 40,
44
+ borderWidth: 1,
45
+ borderColor: '#FF5F00'
46
+ },
47
+ retryButtonText: {
48
+ color: '#FF5F00',
49
+ fontSize: 16,
50
+ fontWeight: '500',
51
+ textAlign: 'center'
52
+ }
53
+ });
54
+ const DefaultFallback = ({ onReload }) => {
55
+ return (<View style={styles.container}>
56
+ <Image source={{
57
+ uri: 'https://dpubstatic.udache.com/static/dpubimg/Vak5mZvezPpKV5ZJI6P9b_drn-fallbak.png'
58
+ }} style={styles.errorImage} resizeMode="contain"/>
59
+ <Text style={styles.errorText}>网络出了点问题,请查看网络环境</Text>
60
+ <TouchableOpacity style={styles.retryButton} onPress={onReload} activeOpacity={0.7}>
61
+ <Text style={styles.retryButtonText}>点击重试</Text>
62
+ </TouchableOpacity>
63
+ </View>);
64
+ };
65
+ const DefaultLoading = () => {
66
+ return (<View style={styles.container}>
67
+ <FastImage style={styles.loadingImage} source={{
68
+ uri: 'https://dpubstatic.udache.com/static/dpubimg/439jiCVOtNOnEv9F2LaDs_loading.gif'
69
+ }} resizeMode={FastImage.resizeMode.contain}></FastImage>
70
+ </View>);
71
+ };
72
+ const AsyncSuspense = ({ type, chunkName, moduleId, innerProps, getLoading, getFallback, getChildren }) => {
73
+ const [status, setStatus] = useState('pending');
74
+ const chunkLoaded = asyncChunkMap.has(moduleId);
75
+ const loadChunkPromise = useRef(null);
76
+ const reloadPage = useCallback(() => {
77
+ setStatus('pending');
78
+ }, []);
79
+ useEffect(() => {
80
+ let cancelled = false;
81
+ if (!chunkLoaded && status === 'pending') {
82
+ if (loadChunkPromise.current) {
83
+ loadChunkPromise
84
+ .current.then((res) => {
85
+ if (cancelled)
86
+ return;
87
+ asyncChunkMap.set(moduleId, res);
88
+ setStatus('loaded');
89
+ })
90
+ .catch((e) => {
91
+ if (cancelled)
92
+ return;
93
+ if (type === 'component') {
94
+ global.__mpxAppCbs.lazyLoad.forEach((cb) => {
95
+ // eslint-disable-next-line node/no-callback-literal
96
+ cb({
97
+ type: 'subpackage',
98
+ subpackage: [chunkName],
99
+ errMsg: `loadSubpackage: ${e.type}`
100
+ });
101
+ });
102
+ }
103
+ if (type === 'page' && typeof mpxGlobal.__mpx.config?.rnConfig?.onLazyLoadPageError === 'function') {
104
+ mpxGlobal.__mpx.config.rnConfig.onLazyLoadPageError({
105
+ subpackage: chunkName,
106
+ errType: e.type
107
+ });
108
+ }
109
+ loadChunkPromise.current = null;
110
+ setStatus('error');
111
+ });
112
+ }
113
+ }
114
+ return () => {
115
+ cancelled = true;
116
+ };
117
+ }, [status]);
118
+ if (chunkLoaded) {
119
+ const Comp = asyncChunkMap.get(moduleId);
120
+ return createElement(Comp, innerProps);
121
+ }
122
+ else if (status === 'error') {
123
+ if (type === 'page') {
124
+ const fallback = getFallback ? getFallback() : DefaultFallback;
125
+ return createElement(fallback, { onReload: reloadPage });
126
+ }
127
+ else {
128
+ return getFallback ? createElement(getFallback(), innerProps) : null;
129
+ }
130
+ }
131
+ else {
132
+ if (!loadChunkPromise.current) {
133
+ loadChunkPromise.current = getChildren();
134
+ }
135
+ if (type === 'page') {
136
+ const loading = getLoading ? getLoading() : DefaultLoading;
137
+ return createElement(loading);
138
+ }
139
+ else {
140
+ return getFallback ? createElement(getFallback(), innerProps) : null;
141
+ }
142
+ }
143
+ };
144
+ AsyncSuspense.displayName = 'MpxAsyncSuspense';
145
+ export default AsyncSuspense;
@@ -42,6 +42,7 @@ import { getCurrentPage, splitProps, splitStyle, useLayout, useTransformStyle, w
42
42
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
43
43
  import useNodesRef from './useNodesRef';
44
44
  import { RouteContext, FormContext } from './context';
45
+ import Portal from './mpx-portal';
45
46
  const LOADING_IMAGE_URI = 'data:image/png;base64,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';
46
47
  const TypeColorMap = {
47
48
  default: ['#F8F8F8', '#DEDEDE', '35,35,35', '#F7F7F7'],
@@ -167,7 +168,7 @@ const Button = forwardRef((buttonProps, ref) => {
167
168
  const defaultTextStyle = extendObject({}, styles.text, isMiniSize ? styles.textMini : {}, { color: plain ? plainTextColor : normalTextColor });
168
169
  const defaultStyle = extendObject({}, defaultViewStyle, defaultTextStyle);
169
170
  const styleObj = extendObject({}, defaultStyle, style, isHover ? hoverStyle : {});
170
- const { hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
171
+ const { hasPositionFixed, hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
171
172
  const nodeRef = useRef(null);
172
173
  useNodesRef(props, ref, nodeRef, { style: normalStyle });
173
174
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
@@ -262,9 +263,13 @@ const Button = forwardRef((buttonProps, ref) => {
262
263
  textStyle,
263
264
  textProps
264
265
  }));
265
- return enableHover
266
+ const finalComponent = enableHover
266
267
  ? createElement(GestureDetector, { gesture: gesture }, baseButton)
267
268
  : baseButton;
269
+ if (hasPositionFixed) {
270
+ return createElement(Portal, null, finalComponent);
271
+ }
272
+ return finalComponent;
268
273
  });
269
274
  Button.displayName = 'MpxButton';
270
275
  export default Button;
@@ -1,4 +1,5 @@
1
1
  import { WEBVIEW_TARGET, registerWebviewProperties } from './utils';
2
+ import { extendObject } from '../utils';
2
3
  const PROPERTIES = {
3
4
  crossOrigin: undefined,
4
5
  height: undefined,
@@ -50,10 +51,7 @@ export class Image {
50
51
  this[key] = value;
51
52
  }
52
53
  }
53
- callbackFn({
54
- ...message.payload,
55
- target: this
56
- });
54
+ callbackFn(extendObject({}, message.payload, { target: this }));
57
55
  }
58
56
  });
59
57
  }
@@ -23,6 +23,7 @@ import './CanvasGradient';
23
23
  import { createImage as canvasCreateImage } from './Image';
24
24
  import { createImageData as canvasCreateImageData } from './ImageData';
25
25
  import { useConstructorsRegistry } from './constructorsRegistry';
26
+ import Portal from '../mpx-portal';
26
27
  const stylesheet = StyleSheet.create({
27
28
  container: { overflow: 'hidden', flex: 0 },
28
29
  webview: {
@@ -41,7 +42,7 @@ const _Canvas = forwardRef((props = {}, ref) => {
41
42
  const { style = {}, originWhitelist = ['*'], 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
42
43
  const [isLoaded, setIsLoaded] = useState(false);
43
44
  const nodeRef = useRef(null);
44
- const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(extendObject({}, style, stylesheet.container), {
45
+ const { normalStyle, hasSelfPercent, hasPositionFixed, setWidth, setHeight } = useTransformStyle(extendObject({}, style, stylesheet.container), {
45
46
  enableVar,
46
47
  externalVarContext,
47
48
  parentFontSize,
@@ -110,10 +111,7 @@ const _Canvas = forwardRef((props = {}, ref) => {
110
111
  const postMessage = useCallback(async (message) => {
111
112
  if (!canvasRef.current?.bus)
112
113
  return;
113
- const { type, payload } = await canvasRef.current.bus.post({
114
- id: ID(),
115
- ...message
116
- });
114
+ const { type, payload } = await canvasRef.current.bus.post(extendObject({ id: ID() }, message));
117
115
  switch (type) {
118
116
  case 'error': {
119
117
  const { binderror } = props;
@@ -142,7 +140,7 @@ const _Canvas = forwardRef((props = {}, ref) => {
142
140
  canvasRef.current.listeners.splice(canvasRef.current.listeners.indexOf(listener), 1);
143
141
  };
144
142
  const onMessage = useCallback((e) => {
145
- let data = JSON.parse(e.nativeEvent.data);
143
+ const data = JSON.parse(e.nativeEvent.data);
146
144
  switch (data.type) {
147
145
  case 'error': {
148
146
  const { binderror } = props;
@@ -156,27 +154,27 @@ const _Canvas = forwardRef((props = {}, ref) => {
156
154
  break;
157
155
  }
158
156
  default: {
157
+ const newData = {};
158
+ // createLinearGradient 方法调用需要在 constructors 中需要注册 CanvasGradient
159
+ const constructor = constructors[data.meta.constructor];
159
160
  if (data.payload) {
160
- // createLinearGradient 方法调用需要在 constructors 中需要注册 CanvasGradient
161
- const constructor = constructors[data.meta.constructor];
162
161
  if (constructor) {
163
162
  const { args, payload } = data;
164
163
  // RN 端同步生成一个 CanvasGradient 的实例
165
164
  const object = constructor.constructLocally(canvasRef.current, ...args);
166
- Object.assign(object, payload, {
165
+ extendObject(object, payload, {
167
166
  [WEBVIEW_TARGET]: data.meta.target
168
167
  });
169
- data = {
170
- ...data,
168
+ extendObject(newData, data, {
171
169
  payload: object
172
- };
170
+ });
173
171
  }
174
172
  for (const listener of canvasRef.current.listeners) {
175
- listener(data.payload);
173
+ listener(constructor ? newData.payload : data.payload);
176
174
  }
177
175
  }
178
176
  if (canvasRef.current.bus) {
179
- canvasRef.current.bus.handle(data);
177
+ canvasRef.current.bus.handle(constructor && data.payload ? newData : data);
180
178
  }
181
179
  }
182
180
  }
@@ -192,9 +190,10 @@ const _Canvas = forwardRef((props = {}, ref) => {
192
190
  node: canvasRef.current,
193
191
  context: context2D
194
192
  });
195
- if (__mpx_mode__ !== 'ios') {
193
+ let canvasComponent;
194
+ if (__mpx_mode__ === 'android') {
196
195
  const isAndroid9 = Platform.Version >= 28;
197
- return createElement(View, innerProps, createElement(WebView, {
196
+ canvasComponent = createElement(View, innerProps, createElement(WebView, {
198
197
  ref: (element) => {
199
198
  if (canvasRef.current) {
200
199
  canvasRef.current.webview = element;
@@ -217,7 +216,7 @@ const _Canvas = forwardRef((props = {}, ref) => {
217
216
  allowUniversalAccessFromFileURLs: true
218
217
  }));
219
218
  }
220
- return createElement(View, innerProps, createElement(WebView, {
219
+ canvasComponent = createElement(View, innerProps, createElement(WebView, {
221
220
  ref: (element) => {
222
221
  if (canvasRef.current) {
223
222
  canvasRef.current.webview = element;
@@ -230,6 +229,10 @@ const _Canvas = forwardRef((props = {}, ref) => {
230
229
  onLoad: onLoad,
231
230
  scrollEnabled: false
232
231
  }));
232
+ if (hasPositionFixed) {
233
+ canvasComponent = createElement(Portal, null, canvasComponent);
234
+ }
235
+ return canvasComponent;
233
236
  });
234
237
  _Canvas.displayName = 'mpxCanvas';
235
238
  export default _Canvas;
@@ -8,6 +8,7 @@ import { FormContext, CheckboxGroupContext } from './context';
8
8
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
9
9
  import useNodesRef from './useNodesRef';
10
10
  import { useLayout, useTransformStyle, wrapChildren, extendObject } from './utils';
11
+ import Portal from './mpx-portal';
11
12
  const CheckboxGroup = forwardRef((props, ref) => {
12
13
  const propsRef = useRef({});
13
14
  propsRef.current = props;
@@ -23,7 +24,7 @@ const CheckboxGroup = forwardRef((props, ref) => {
23
24
  flexWrap: 'wrap'
24
25
  };
25
26
  const styleObj = extendObject({}, defaultStyle, style);
26
- const { hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
27
+ const { hasPositionFixed, hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
27
28
  const nodeRef = useRef(null);
28
29
  useNodesRef(props, ref, nodeRef, { style: normalStyle });
29
30
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
@@ -81,10 +82,14 @@ const CheckboxGroup = forwardRef((props, ref) => {
81
82
  notifyChange
82
83
  };
83
84
  }, []);
84
- return createElement(View, innerProps, createElement(CheckboxGroupContext.Provider, { value: contextValue }, wrapChildren(props, {
85
+ const finalComponent = createElement(View, innerProps, createElement(CheckboxGroupContext.Provider, { value: contextValue }, wrapChildren(props, {
85
86
  hasVarDec,
86
87
  varContext: varContextRef.current
87
88
  })));
89
+ if (hasPositionFixed) {
90
+ return createElement(Portal, null, finalComponent);
91
+ }
92
+ return finalComponent;
88
93
  });
89
94
  CheckboxGroup.displayName = 'MpxCheckboxGroup';
90
95
  export default CheckboxGroup;
@@ -12,6 +12,7 @@ import useNodesRef from './useNodesRef';
12
12
  import Icon from './mpx-icon';
13
13
  import { splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren, extendObject } from './utils';
14
14
  import { CheckboxGroupContext, LabelContext } from './context';
15
+ import Portal from './mpx-portal';
15
16
  const styles = StyleSheet.create({
16
17
  container: {
17
18
  flexDirection: 'row',
@@ -63,7 +64,7 @@ const Checkbox = forwardRef((checkboxProps, ref) => {
63
64
  bindtap && bindtap(getCustomEvent('tap', evt, { layoutRef }, props));
64
65
  onChange(evt);
65
66
  };
66
- const { hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
67
+ const { hasPositionFixed, hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
67
68
  const nodeRef = useRef(null);
68
69
  useNodesRef(props, ref, nodeRef, {
69
70
  style: extendObject({}, defaultStyle, normalStyle),
@@ -114,7 +115,7 @@ const Checkbox = forwardRef((checkboxProps, ref) => {
114
115
  }
115
116
  }
116
117
  }, [checked]);
117
- return createElement(View, innerProps, createElement(View, { style: defaultStyle }, createElement(Icon, {
118
+ const finalComponent = createElement(View, innerProps, createElement(View, { style: defaultStyle }, createElement(Icon, {
118
119
  type: 'success_no_circle',
119
120
  size: 18,
120
121
  color: disabled ? '#ADADAD' : color,
@@ -125,6 +126,10 @@ const Checkbox = forwardRef((checkboxProps, ref) => {
125
126
  textStyle,
126
127
  textProps
127
128
  }));
129
+ if (hasPositionFixed) {
130
+ return createElement(Portal, null, finalComponent);
131
+ }
132
+ return finalComponent;
128
133
  });
129
134
  Checkbox.displayName = 'MpxCheckbox';
130
135
  export default Checkbox;
@@ -17,6 +17,7 @@ import Cancel from './icons/cancel.png';
17
17
  import Download from './icons/download.png';
18
18
  import Search from './icons/search.png';
19
19
  import Clear from './icons/clear.png';
20
+ import Portal from '../mpx-portal';
20
21
  const IconTypeMap = new Map([
21
22
  ['success', Success],
22
23
  ['success_no_circle', SuccessNoCircle],
@@ -33,7 +34,7 @@ const Icon = forwardRef((props, ref) => {
33
34
  const source = IconTypeMap.get(type);
34
35
  const defaultStyle = { width: ~~size, height: ~~size };
35
36
  const styleObj = extendObject({}, defaultStyle, style);
36
- const { hasSelfPercent, normalStyle, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
37
+ const { hasPositionFixed, hasSelfPercent, normalStyle, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
37
38
  const nodeRef = useRef(null);
38
39
  useNodesRef(props, ref, nodeRef, { style: normalStyle });
39
40
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
@@ -44,7 +45,11 @@ const Icon = forwardRef((props, ref) => {
44
45
  }), [], {
45
46
  layoutRef
46
47
  });
47
- return createElement(Image, innerProps);
48
+ const finalComponent = createElement(Image, innerProps);
49
+ if (hasPositionFixed) {
50
+ return createElement(Portal, null, finalComponent);
51
+ }
52
+ return finalComponent;
48
53
  });
49
54
  Icon.displayName = 'MpxIcon';
50
55
  export default Icon;
@@ -17,6 +17,7 @@ import { SvgCssUri } from 'react-native-svg/css';
17
17
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
18
18
  import useNodesRef from './useNodesRef';
19
19
  import { SVG_REGEXP, useLayout, useTransformStyle, renderImage, extendObject } from './utils';
20
+ import Portal from './mpx-portal';
20
21
  const DEFAULT_IMAGE_WIDTH = 320;
21
22
  const DEFAULT_IMAGE_HEIGHT = 240;
22
23
  const cropMode = [
@@ -79,7 +80,7 @@ const Image = forwardRef((props, ref) => {
79
80
  setLoaded(true);
80
81
  }
81
82
  };
82
- const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
83
+ const { hasPositionFixed, hasSelfPercent, normalStyle, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
83
84
  const { layoutRef, layoutStyle, layoutProps } = useLayout({
84
85
  props,
85
86
  hasSelfPercent,
@@ -255,6 +256,8 @@ const Image = forwardRef((props, ref) => {
255
256
  state.current = {};
256
257
  setLoaded(true);
257
258
  }
259
+ }, () => {
260
+ setLoaded(true);
258
261
  });
259
262
  }
260
263
  }, [src, isSvg, isLayoutMode]);
@@ -268,25 +271,35 @@ const Image = forwardRef((props, ref) => {
268
271
  ], {
269
272
  layoutRef
270
273
  });
271
- const SvgImage = createElement(View, innerProps, createElement(SvgCssUri, {
272
- uri: src,
273
- onLayout: onSvgLoad,
274
- onError: binderror && onSvgError,
275
- style: extendObject({ transformOrigin: 'left top' }, modeStyle)
276
- }));
277
- const BaseImage = renderImage(extendObject({
278
- source: { uri: src },
279
- resizeMode: resizeMode,
280
- onLoad: bindload && onImageLoad,
281
- onError: binderror && onImageError,
282
- style: extendObject({
283
- transformOrigin: 'left top',
284
- width: isCropMode ? imageWidth : '100%',
285
- height: isCropMode ? imageHeight : '100%'
286
- }, isCropMode ? modeStyle : {})
287
- }, isLayoutMode ? {} : innerProps), enableFastImage);
288
- const LayoutImage = createElement(View, innerProps, loaded && BaseImage);
289
- return isSvg ? SvgImage : isLayoutMode ? LayoutImage : BaseImage;
274
+ function renderSvgImage() {
275
+ return createElement(View, innerProps, createElement(SvgCssUri, {
276
+ uri: src,
277
+ onLayout: onSvgLoad,
278
+ onError: binderror && onSvgError,
279
+ style: extendObject({ transformOrigin: 'left top' }, modeStyle)
280
+ }));
281
+ }
282
+ function renderBaseImage() {
283
+ return renderImage(extendObject({
284
+ source: { uri: src },
285
+ resizeMode: resizeMode,
286
+ onLoad: bindload && onImageLoad,
287
+ onError: binderror && onImageError,
288
+ style: extendObject({
289
+ transformOrigin: 'left top',
290
+ width: isCropMode ? imageWidth : '100%',
291
+ height: isCropMode ? imageHeight : '100%'
292
+ }, isCropMode ? modeStyle : {})
293
+ }, isLayoutMode ? {} : innerProps), enableFastImage);
294
+ }
295
+ function renderLayoutImage() {
296
+ return createElement(View, innerProps, loaded && renderBaseImage());
297
+ }
298
+ const finalComponent = isSvg ? renderSvgImage() : isLayoutMode ? renderLayoutImage() : renderBaseImage();
299
+ if (hasPositionFixed) {
300
+ return createElement(Portal, null, finalComponent);
301
+ }
302
+ return finalComponent;
290
303
  });
291
304
  Image.displayName = 'mpx-image';
292
305
  export default Image;
@@ -44,6 +44,7 @@ import { useUpdateEffect, useTransformStyle, useLayout, extendObject, isIOS } fr
44
44
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
45
45
  import useNodesRef from './useNodesRef';
46
46
  import { FormContext, KeyboardAvoidContext } from './context';
47
+ import Portal from './mpx-portal';
47
48
  const keyboardTypeMap = {
48
49
  text: 'default',
49
50
  number: 'numeric',
@@ -83,7 +84,7 @@ const Input = forwardRef((props, ref) => {
83
84
  const styleObj = extendObject({ padding: 0, backgroundColor: '#fff' }, style, multiline && autoHeight
84
85
  ? { height: 'auto', minHeight: Math.max(style?.minHeight || 35, contentHeight) }
85
86
  : {});
86
- const { hasSelfPercent, normalStyle, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
87
+ const { hasPositionFixed, hasSelfPercent, normalStyle, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
87
88
  const nodeRef = useRef(null);
88
89
  useNodesRef(props, ref, nodeRef, {
89
90
  style: normalStyle
@@ -289,7 +290,11 @@ const Input = forwardRef((props, ref) => {
289
290
  ], {
290
291
  layoutRef
291
292
  });
292
- return createElement(TextInput, innerProps);
293
+ const finalComponent = createElement(TextInput, innerProps);
294
+ if (hasPositionFixed) {
295
+ return createElement(Portal, null, finalComponent);
296
+ }
297
+ return finalComponent;
293
298
  });
294
299
  Input.displayName = 'MpxInput';
295
300
  export default Input;
@@ -8,6 +8,7 @@ import useInnerProps, { getCustomEvent } from './getInnerListeners';
8
8
  import useNodesRef from './useNodesRef';
9
9
  import { splitProps, splitStyle, useLayout, useTransformStyle, wrapChildren, extendObject } from './utils';
10
10
  import { LabelContext } from './context';
11
+ import Portal from './mpx-portal';
11
12
  const Label = forwardRef((labelProps, ref) => {
12
13
  const { textProps, innerProps: props = {} } = splitProps(labelProps);
13
14
  const propsRef = useRef({});
@@ -17,7 +18,7 @@ const Label = forwardRef((labelProps, ref) => {
17
18
  flexDirection: 'row'
18
19
  };
19
20
  const styleObj = extendObject({}, defaultStyle, style);
20
- const { hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
21
+ const { hasPositionFixed, hasSelfPercent, normalStyle, hasVarDec, varContextRef, setWidth, setHeight } = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
21
22
  const nodeRef = useRef(null);
22
23
  useNodesRef(props, ref, nodeRef, { style: normalStyle });
23
24
  const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef });
@@ -40,12 +41,16 @@ const Label = forwardRef((labelProps, ref) => {
40
41
  }), [], {
41
42
  layoutRef
42
43
  });
43
- return createElement(View, innerProps, createElement(LabelContext.Provider, { value: contextRef }, wrapChildren(props, {
44
+ const finalComponent = createElement(View, innerProps, createElement(LabelContext.Provider, { value: contextRef }, wrapChildren(props, {
44
45
  hasVarDec,
45
46
  varContext: varContextRef.current,
46
47
  textStyle,
47
48
  textProps
48
49
  })));
50
+ if (hasPositionFixed) {
51
+ return createElement(Portal, null, finalComponent);
52
+ }
53
+ return finalComponent;
49
54
  });
50
55
  Label.displayName = 'MpxLabel';
51
56
  export default Label;