@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
@@ -68,6 +68,7 @@ import { StyleSheet, View } from 'react-native';
68
68
  import { splitProps, useTransformStyle, useLayout, extendObject } from './utils';
69
69
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
70
70
  import useNodesRef from './useNodesRef';
71
+ import Portal from './mpx-portal';
71
72
  const styles = StyleSheet.create({
72
73
  container: {
73
74
  width: 300,
@@ -85,7 +86,7 @@ const MpxVideo = forwardRef((videoProps, ref) => {
85
86
  const videoInfoRef = useRef({});
86
87
  const propsRef = useRef({});
87
88
  propsRef.current = props;
88
- const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(extendObject({}, styles.container, style), {
89
+ const { normalStyle, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(extendObject({}, styles.container, style), {
89
90
  enableVar,
90
91
  externalVarContext,
91
92
  parentFontSize,
@@ -243,6 +244,10 @@ const MpxVideo = forwardRef((videoProps, ref) => {
243
244
  'bindcontrolstoggle',
244
245
  'bindseekcomplete'
245
246
  ], { layoutRef });
246
- return createElement(View, { style: extendObject({}, normalStyle, layoutStyle), ref: viewRef }, createElement(Video, innerProps));
247
+ let videoComponent = createElement(View, { style: extendObject({}, normalStyle, layoutStyle), ref: viewRef }, createElement(Video, innerProps));
248
+ if (hasPositionFixed) {
249
+ videoComponent = createElement(Portal, null, videoComponent);
250
+ }
251
+ return videoComponent;
247
252
  });
248
253
  export default MpxVideo;
@@ -57,7 +57,7 @@ const normalizeStyle = (style = {}) => {
57
57
  const isPercent = (val) => typeof val === 'string' && PERCENT_REGEX.test(val);
58
58
  const isBackgroundSizeKeyword = (val) => typeof val === 'string' && /^cover|contain$/.test(val);
59
59
  const isNeedLayout = (preImageInfo) => {
60
- const { sizeList, backgroundPosition, linearInfo } = preImageInfo;
60
+ const { sizeList, backgroundPosition, linearInfo, type } = preImageInfo;
61
61
  const [width, height] = sizeList;
62
62
  const bp = backgroundPosition;
63
63
  // 含有百分号,center 需计算布局
@@ -66,7 +66,8 @@ const isNeedLayout = (preImageInfo) => {
66
66
  (isPercent(width) && height === 'auto') ||
67
67
  isPercent(bp[1]) ||
68
68
  isPercent(bp[3]) ||
69
- isDiagonalAngle(linearInfo);
69
+ isDiagonalAngle(linearInfo) ||
70
+ (type === 'linear' && (isPercent(height) || isPercent(width)));
70
71
  };
71
72
  const checkNeedLayout = (preImageInfo) => {
72
73
  const { sizeList } = preImageInfo;
@@ -155,7 +156,7 @@ function backgroundPosition(imageProps, preImageInfo, imageSize, layoutInfo) {
155
156
  }
156
157
  // background-size 转换
157
158
  function backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo) {
158
- const sizeList = preImageInfo.sizeList;
159
+ const { sizeList, type } = preImageInfo;
159
160
  if (!sizeList)
160
161
  return;
161
162
  const { width: layoutWidth, height: layoutHeight } = layoutInfo || {};
@@ -202,10 +203,20 @@ function backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo) {
202
203
  else { // 数值类型 ImageStyle
203
204
  // 数值类型设置为 stretch
204
205
  imageProps.resizeMode = 'stretch';
205
- dimensions = {
206
- width: isPercent(width) ? width : +width,
207
- height: isPercent(height) ? height : +height
208
- };
206
+ if (type === 'linear' && (!layoutWidth || !layoutHeight)) {
207
+ // ios linear 组件只要重新触发渲染,在渲染过程中外层容器 width 或者 height 被设置为 0,通过设置 % 的方式会渲染不出来,即使后面再更新为正常宽高也渲染不出来
208
+ // 所以 hack 手动先将 linear 宽高也设置为 0,后面再更新为正确的数值或 %。
209
+ dimensions = {
210
+ width: 0,
211
+ height: 0
212
+ };
213
+ }
214
+ else {
215
+ dimensions = {
216
+ width: isPercent(width) ? width : +width,
217
+ height: isPercent(height) ? height : +height
218
+ };
219
+ }
209
220
  }
210
221
  }
211
222
  // 样式合并
@@ -523,10 +534,8 @@ function useWrapImage(imageStyle, innerStyle, enableFastImage) {
523
534
  setShow(true);
524
535
  }
525
536
  };
526
- return <View key='backgroundImage' {...needLayout ? { onLayout } : null} style={{ ...inheritStyle(innerStyle), ...StyleSheet.absoluteFillObject, overflow: 'hidden' }}>
527
- {show && type === 'linear' && <LinearGradient useAngle={true} {...imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current)}/>}
528
- {show && type === 'image' && (renderImage(imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current), enableFastImage))}
529
- </View>;
537
+ const backgroundProps = extendObject({ key: 'backgroundImage' }, needLayout ? { onLayout } : {}, { style: extendObject({}, inheritStyle(innerStyle), StyleSheet.absoluteFillObject, { overflow: 'hidden' }) });
538
+ return createElement(View, backgroundProps, show && type === 'linear' && createElement(LinearGradient, extendObject({ useAngle: true }, imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current))), show && type === 'image' && renderImage(imageStyleToProps(preImageInfo, sizeInfo.current, layoutInfo.current), enableFastImage));
530
539
  }
531
540
  function wrapWithChildren(props, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps, innerStyle, enableFastImage }) {
532
541
  const children = wrapChildren(props, {
@@ -579,21 +588,14 @@ const _View = forwardRef((viewProps, ref) => {
579
588
  ? catchtransitionend
580
589
  : isFunction(bindtransitionend)
581
590
  ? bindtransitionend
582
- : null;
583
- const { enableStyleAnimation, animationStyle } = useAnimationHooks(transitionend
584
- ? {
585
- layoutRef,
586
- animation,
587
- enableAnimation,
588
- style: viewStyle,
589
- transitionend
590
- }
591
- : {
592
- layoutRef,
593
- animation,
594
- enableAnimation,
595
- style: viewStyle
596
- });
591
+ : undefined;
592
+ const { enableStyleAnimation, animationStyle } = useAnimationHooks({
593
+ layoutRef,
594
+ animation,
595
+ enableAnimation,
596
+ style: viewStyle,
597
+ transitionend
598
+ });
597
599
  const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
598
600
  ref: nodeRef,
599
601
  style: enableStyleAnimation ? [viewStyle, animationStyle] : viewStyle
@@ -1,6 +1,7 @@
1
1
  import { forwardRef, useRef, useContext, useMemo, useState } from 'react';
2
2
  import { warn, isFunction } from '@mpxjs/utils';
3
3
  import Portal from './mpx-portal/index';
4
+ import { usePreventRemove } from '@react-navigation/native';
4
5
  import { getCustomEvent } from './getInnerListeners';
5
6
  import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab } from '@mpxjs/api-proxy';
6
7
  import { WebView } from 'react-native-webview';
@@ -55,8 +56,8 @@ const _WebView = forwardRef((props, ref) => {
55
56
  const webViewRef = useRef(null);
56
57
  const fristLoaded = useRef(false);
57
58
  const isLoadError = useRef(false);
59
+ const isNavigateBack = useRef(false);
58
60
  const statusCode = useRef('');
59
- const [isLoaded, setIsLoaded] = useState(true);
60
61
  const defaultWebViewStyle = {
61
62
  position: 'absolute',
62
63
  left: 0,
@@ -64,33 +65,40 @@ const _WebView = forwardRef((props, ref) => {
64
65
  top: 0,
65
66
  bottom: 0
66
67
  };
67
- const canGoBack = useRef(false);
68
- const isNavigateBack = useRef(false);
69
- const beforeRemoveHandle = (e) => {
70
- if (canGoBack.current && !isNavigateBack.current) {
68
+ const navigation = useNavigation();
69
+ const [isIntercept, setIsIntercept] = useState(false);
70
+ usePreventRemove(isIntercept, (event) => {
71
+ const { data } = event;
72
+ if (isNavigateBack.current) {
73
+ navigation?.dispatch(data.action);
74
+ }
75
+ else {
71
76
  webViewRef.current?.goBack();
72
- e.preventDefault();
73
77
  }
74
78
  isNavigateBack.current = false;
75
- };
76
- const navigation = useNavigation();
77
- // useEffect(() => {
78
- // let beforeRemoveSubscription:any
79
- // if (__mpx_mode__ !== 'ios') {
80
- // beforeRemoveSubscription = navigation?.addListener?.('beforeRemove', beforeRemoveHandle)
81
- // }
82
- // return () => {
83
- // if (isFunction(beforeRemoveSubscription)) {
84
- // beforeRemoveSubscription()
85
- // }
86
- // }
87
- // }, [])
79
+ });
88
80
  useNodesRef(props, ref, webViewRef, {
89
81
  style: defaultWebViewStyle
90
82
  });
83
+ const hostValidate = (url) => {
84
+ const host = url && new URL(url).host;
85
+ const hostWhitelists = mpx.config.rnConfig?.webviewConfig?.hostWhitelists || [];
86
+ if (hostWhitelists.length) {
87
+ return hostWhitelists.some((item) => {
88
+ return host.endsWith(item);
89
+ });
90
+ }
91
+ else {
92
+ return true;
93
+ }
94
+ };
91
95
  if (!src) {
92
96
  return null;
93
97
  }
98
+ if (!hostValidate(src)) {
99
+ console.error('访问页面域名不符合domainWhiteLists白名单配置,请确认是否正确配置该域名白名单');
100
+ return null;
101
+ }
94
102
  const _reload = function () {
95
103
  if (__mpx_mode__ !== 'ios') {
96
104
  fristLoaded.current = false; // 安卓需要重新设置
@@ -131,16 +139,19 @@ const _WebView = forwardRef((props, ref) => {
131
139
  };
132
140
  const _changeUrl = function (navState) {
133
141
  if (navState.navigationType) { // navigationType这个事件在页面开始加载时和页面加载完成时都会被触发所以判断这个避免其他无效触发执行该逻辑
134
- canGoBack.current = navState.canGoBack;
135
142
  currentPage.__webViewUrl = navState.url;
143
+ setIsIntercept(navState.canGoBack);
136
144
  }
137
145
  };
138
146
  const _onLoadProgress = function (event) {
139
147
  if (__mpx_mode__ !== 'ios') {
140
- canGoBack.current = event.nativeEvent.canGoBack;
148
+ setIsIntercept(event.nativeEvent.canGoBack);
141
149
  }
142
150
  };
143
151
  const _message = function (res) {
152
+ if (!hostValidate(res.nativeEvent?.url)) {
153
+ return;
154
+ }
144
155
  let data = {};
145
156
  let asyncCallback;
146
157
  const navObj = promisify({ redirectTo, navigateTo, navigateBack, reLaunch, switchTab });
@@ -192,7 +203,7 @@ const _WebView = forwardRef((props, ref) => {
192
203
  break;
193
204
  default:
194
205
  if (type) {
195
- const implement = mpx.config.webviewConfig.apiImplementations && mpx.config.webviewConfig.apiImplementations[type];
206
+ const implement = mpx.config.rnConfig.webviewConfig && mpx.config.rnConfig.webviewConfig.apiImplementations && mpx.config.rnConfig.webviewConfig.apiImplementations[type];
196
207
  if (isFunction(implement)) {
197
208
  asyncCallback = Promise.resolve(implement(...params));
198
209
  }
@@ -227,7 +238,6 @@ const _WebView = forwardRef((props, ref) => {
227
238
  };
228
239
  const onLoadEndHandle = function (res) {
229
240
  fristLoaded.current = true;
230
- setIsLoaded(true);
231
241
  const src = res.nativeEvent?.url;
232
242
  if (isLoadError.current) {
233
243
  isLoadError.current = false;
@@ -275,18 +285,13 @@ const _WebView = forwardRef((props, ref) => {
275
285
  setPageLoadErr(true);
276
286
  }
277
287
  };
278
- const onLoadStart = function () {
279
- if (!fristLoaded.current) {
280
- setIsLoaded(false);
281
- }
282
- };
283
288
  return (<Portal>
284
289
  {pageLoadErr
285
290
  ? (<View style={[styles.loadErrorContext, defaultWebViewStyle]}>
286
291
  <View style={styles.loadErrorText}><Text style={{ fontSize: 14, color: '#999999' }}>{currentErrorText.text}</Text></View>
287
292
  <View style={styles.loadErrorButton} onTouchEnd={_reload}><Text style={{ fontSize: 12, color: '#666666' }}>{currentErrorText.button}</Text></View>
288
293
  </View>)
289
- : (<WebView style={defaultWebViewStyle} pointerEvents={isLoaded ? 'auto' : 'none'} source={{ uri: src }} ref={webViewRef} javaScriptEnabled={true} onNavigationStateChange={_changeUrl} onMessage={_message} injectedJavaScript={injectedJavaScript} onLoadProgress={_onLoadProgress} onLoadEnd={onLoadEnd} onHttpError={onHttpError} onError={onError} onLoadStart={onLoadStart} allowsBackForwardNavigationGestures={true}></WebView>)}
294
+ : (<WebView style={defaultWebViewStyle} source={{ uri: src }} ref={webViewRef} javaScriptEnabled={true} onNavigationStateChange={_changeUrl} onMessage={_message} injectedJavaScript={injectedJavaScript} onLoadProgress={_onLoadProgress} onLoadEnd={onLoadEnd} onHttpError={onHttpError} onError={onError} allowsBackForwardNavigationGestures={true}></WebView>)}
290
295
  </Portal>);
291
296
  });
292
297
  _WebView.displayName = 'MpxWebview';
@@ -1,6 +1,7 @@
1
1
  import { useEffect, useMemo, useRef } from 'react';
2
2
  import { Easing, useSharedValue, withTiming, useAnimatedStyle, withSequence, withDelay, makeMutable, cancelAnimation, runOnJS } from 'react-native-reanimated';
3
3
  import { error, hasOwn, collectDataset } from '@mpxjs/utils';
4
+ import { useRunOnJSCallback } from './utils';
4
5
  // 微信 timingFunction 和 RN Easing 对应关系
5
6
  const EasingKey = {
6
7
  linear: Easing.linear,
@@ -48,90 +49,6 @@ const InitialValue = Object.assign({
48
49
  const TransformOrigin = 'transformOrigin';
49
50
  // transform
50
51
  const isTransform = (key) => Object.keys(TransformInitial).includes(key);
51
- // 多value解析
52
- const parseValues = (str, char = ' ') => {
53
- let stack = 0;
54
- let temp = '';
55
- const result = [];
56
- for (let i = 0; i < str.length; i++) {
57
- if (str[i] === '(') {
58
- stack++;
59
- }
60
- else if (str[i] === ')') {
61
- stack--;
62
- }
63
- // 非括号内 或者 非分隔字符且非空
64
- if (stack !== 0 || (str[i] !== char && str[i] !== ' ')) {
65
- temp += str[i];
66
- }
67
- if ((stack === 0 && str[i] === char) || i === str.length - 1) {
68
- result.push(temp);
69
- temp = '';
70
- }
71
- }
72
- return result;
73
- };
74
- // parse string transform, eg: transform: 'rotateX(45deg) rotateZ(0.785398rad)'
75
- const parseTransform = (transformStr) => {
76
- const values = parseValues(transformStr);
77
- const transform = [];
78
- values.forEach(item => {
79
- const match = item.match(/([/\w]+)\((.+)\)/);
80
- if (match && match.length >= 3) {
81
- let key = match[1];
82
- const val = match[2];
83
- switch (key) {
84
- case 'translateX':
85
- case 'translateY':
86
- case 'scaleX':
87
- case 'scaleY':
88
- case 'rotateX':
89
- case 'rotateY':
90
- case 'rotateZ':
91
- case 'rotate':
92
- case 'skewX':
93
- case 'skewY':
94
- case 'perspective':
95
- // rotate 处理成 rotateZ
96
- key = key === 'rotate' ? 'rotateZ' : key;
97
- // 单个值处理
98
- transform.push({ [key]: global.__formatValue(val) });
99
- break;
100
- case 'matrix':
101
- transform.push({ [key]: parseValues(val, ',').map(val => +val) });
102
- break;
103
- case 'translate':
104
- case 'scale':
105
- case 'skew':
106
- case 'translate3d': // x y 支持 z不支持
107
- case 'scale3d': // x y 支持 z不支持
108
- {
109
- // 2 个以上的值处理
110
- key = key.replace('3d', '');
111
- const vals = parseValues(val, ',').splice(0, 3);
112
- // scale(.5) === scaleX(.5) scaleY(.5)
113
- if (vals.length === 1 && key === 'scale') {
114
- vals.push(vals[0]);
115
- }
116
- const xyz = ['X', 'Y', 'Z'];
117
- transform.push(...vals.map((v, index) => {
118
- return { [`${key}${xyz[index] || ''}`]: global.__formatValue(v.trim()) };
119
- }));
120
- break;
121
- }
122
- }
123
- }
124
- });
125
- return transform;
126
- };
127
- // format style
128
- const formatStyle = (style) => {
129
- if (!style.transform || Array.isArray(style.transform))
130
- return style;
131
- return Object.assign({}, style, {
132
- transform: parseTransform(style.transform)
133
- });
134
- };
135
52
  // transform 数组转对象
136
53
  function getTransformObj(transforms) {
137
54
  'worklet';
@@ -140,7 +57,7 @@ function getTransformObj(transforms) {
140
57
  }, {});
141
58
  }
142
59
  export default function useAnimationHooks(props) {
143
- const { style = {}, animation, enableAnimation, transitionend, layoutRef } = props;
60
+ const { style: originalStyle = {}, animation, enableAnimation, transitionend, layoutRef } = props;
144
61
  const enableStyleAnimation = enableAnimation || !!animation;
145
62
  const enableAnimationRef = useRef(enableStyleAnimation);
146
63
  if (enableAnimationRef.current !== enableStyleAnimation) {
@@ -148,7 +65,6 @@ export default function useAnimationHooks(props) {
148
65
  }
149
66
  if (!enableAnimationRef.current)
150
67
  return { enableStyleAnimation: false };
151
- const originalStyle = formatStyle(style);
152
68
  // id 标识
153
69
  const id = animation?.id || -1;
154
70
  // 有动画样式的 style key
@@ -177,7 +93,7 @@ export default function useAnimationHooks(props) {
177
93
  useEffect(() => {
178
94
  // style 更新后同步更新 lastStyleRef & shareValMap
179
95
  updateStyleVal();
180
- }, [style]);
96
+ }, [originalStyle]);
181
97
  // ** 获取动画样式prop & 驱动动画
182
98
  // eslint-disable-next-line react-hooks/rules-of-hooks
183
99
  useEffect(() => {
@@ -260,19 +176,26 @@ export default function useAnimationHooks(props) {
260
176
  };
261
177
  transitionend({
262
178
  type: 'transitionend',
263
- detail: { elapsedTime: duration, finished, current },
179
+ // elapsedTime 对齐wx 单位s
180
+ detail: { elapsedTime: duration ? duration / 1000 : 0, finished, current },
264
181
  target,
265
182
  currentTarget: target,
266
183
  timeStamp: Date.now()
267
184
  });
268
185
  }
186
+ // eslint-disable-next-line react-hooks/rules-of-hooks
187
+ const runOnJSCallbackRef = useRef({
188
+ withTimingCallback
189
+ });
190
+ // eslint-disable-next-line react-hooks/rules-of-hooks
191
+ const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef);
269
192
  // 创建单个animation
270
193
  function getAnimation({ key, value }, { delay, duration, easing }, callback) {
271
194
  const animation = typeof callback === 'function'
272
195
  ? withTiming(value, { duration, easing }, (finished, current) => {
273
196
  callback(finished, current);
274
197
  if (transitionend && finished) {
275
- runOnJS(withTimingCallback)(finished, current, duration);
198
+ runOnJS(runOnJSCallback)('withTimingCallback', finished, current, duration);
276
199
  }
277
200
  })
278
201
  : withTiming(value, { duration, easing });