@mpxjs/webpack-plugin 2.10.15-prelease.1 → 2.10.16-beta.2

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 (70) hide show
  1. package/lib/dependencies/AppEntryDependency.js +2 -2
  2. package/lib/dependencies/RecordModuleIdMapDependency.js +49 -0
  3. package/lib/dependencies/ResolveDependency.js +1 -1
  4. package/lib/helpers.js +2 -0
  5. package/lib/index.js +40 -15
  6. package/lib/json-compiler/helper.js +72 -2
  7. package/lib/json-compiler/index.js +14 -54
  8. package/lib/json-compiler/plugin.js +2 -2
  9. package/lib/loader.js +6 -2
  10. package/lib/native-loader.js +6 -3
  11. package/lib/platform/json/wx/index.js +24 -29
  12. package/lib/platform/style/wx/index.js +8 -1
  13. package/lib/platform/template/wx/component-config/button.js +12 -3
  14. package/lib/platform/template/wx/component-config/camera.js +12 -0
  15. package/lib/platform/template/wx/component-config/component.js +31 -33
  16. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  17. package/lib/react/processJSON.js +39 -71
  18. package/lib/react/processStyles.js +3 -2
  19. package/lib/react/processTemplate.js +6 -6
  20. package/lib/react/script-helper.js +6 -16
  21. package/lib/react/style-helper.js +10 -2
  22. package/lib/runtime/components/react/context.ts +2 -0
  23. package/lib/runtime/components/react/dist/context.js +1 -0
  24. package/lib/runtime/components/react/dist/mpx-camera.jsx +102 -0
  25. package/lib/runtime/components/react/dist/mpx-image.jsx +81 -37
  26. package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +19 -4
  27. package/lib/runtime/components/react/dist/mpx-picker-view/index.jsx +3 -2
  28. package/lib/runtime/components/react/dist/mpx-picker-view-column/index.jsx +9 -6
  29. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItem.jsx +8 -11
  30. package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItemLite.jsx +20 -0
  31. package/lib/runtime/components/react/dist/mpx-portal/index.jsx +5 -1
  32. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +6 -14
  33. package/lib/runtime/components/react/dist/mpx-text.jsx +33 -5
  34. package/lib/runtime/components/react/dist/mpx-view.jsx +1 -1
  35. package/lib/runtime/components/react/dist/mpx-web-view.jsx +1 -1
  36. package/lib/runtime/components/react/dist/utils.jsx +16 -6
  37. package/lib/runtime/components/react/mpx-camera.tsx +167 -0
  38. package/lib/runtime/components/react/mpx-image.tsx +89 -42
  39. package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +31 -4
  40. package/lib/runtime/components/react/mpx-picker-view/index.tsx +4 -1
  41. package/lib/runtime/components/react/mpx-picker-view-column/index.tsx +19 -8
  42. package/lib/runtime/components/react/mpx-picker-view-column/pickerViewColumnItem.tsx +8 -12
  43. package/lib/runtime/components/react/mpx-picker-view-column/pickerViewColumnItemLite.tsx +55 -0
  44. package/lib/runtime/components/react/mpx-portal/index.tsx +8 -2
  45. package/lib/runtime/components/react/mpx-scroll-view.tsx +6 -17
  46. package/lib/runtime/components/react/mpx-text.tsx +38 -5
  47. package/lib/runtime/components/react/mpx-view.tsx +1 -1
  48. package/lib/runtime/components/react/mpx-web-view.tsx +1 -1
  49. package/lib/runtime/components/react/utils.tsx +15 -6
  50. package/lib/runtime/components/web/mpx-input.vue +0 -14
  51. package/lib/script-setup-compiler/index.js +2 -2
  52. package/lib/style-compiler/index.js +3 -2
  53. package/lib/style-compiler/load-postcss-config.js +1 -1
  54. package/lib/style-compiler/plugins/trans-special.js +10 -2
  55. package/lib/style-compiler/strip-conditional-loader.js +155 -15
  56. package/lib/template-compiler/compiler.js +252 -55
  57. package/lib/template-compiler/gen-node-react.js +18 -6
  58. package/lib/template-compiler/index.js +6 -4
  59. package/lib/template-compiler/parse-exps.js +1 -1
  60. package/lib/utils/const.js +2 -1
  61. package/lib/utils/dom-tag-config.js +1 -1
  62. package/lib/utils/env.js +6 -1
  63. package/lib/utils/get-build-tag-component.js +35 -0
  64. package/lib/utils/pre-process-json.js +5 -0
  65. package/lib/web/processJSON.js +44 -16
  66. package/lib/web/processScript.js +1 -1
  67. package/lib/web/processTemplate.js +4 -4
  68. package/lib/web/script-helper.js +19 -9
  69. package/lib/wxss/loader.js +1 -9
  70. package/package.json +12 -4
@@ -40,7 +40,16 @@ const ModeMap = new Map([
40
40
  ...cropMode.map(mode => [mode, 'stretch'])
41
41
  ]);
42
42
  const isNumber = (value) => typeof value === 'number';
43
- const relativeCenteredSize = (viewSize, imageSize) => (viewSize - imageSize) / 2;
43
+ const relativeCenteredSize = (viewSize, imageSize) => {
44
+ return (viewSize - imageSize) / 2;
45
+ };
46
+ // 获取能完全显示图片的缩放比例:长宽方向的缩放比例最小值即为能完全展示的比例
47
+ function getFitScale(width1, height1, width2, height2) {
48
+ return Math.min(width2 / width1, height2 / height1);
49
+ }
50
+ function getFillScale(width1, height1, width2, height2) {
51
+ return Math.max(width2 / width1, height2 / height1);
52
+ }
44
53
  function noMeetCalcRule(isSvg, mode, viewWidth, viewHeight, ratio) {
45
54
  const isMeetSize = viewWidth && viewHeight && ratio;
46
55
  if (isSvg && !isMeetSize)
@@ -49,6 +58,16 @@ function noMeetCalcRule(isSvg, mode, viewWidth, viewHeight, ratio) {
49
58
  return true;
50
59
  return false;
51
60
  }
61
+ const getFixedWidth = (viewWidth, viewHeight, ratio) => {
62
+ if (!ratio)
63
+ return viewWidth;
64
+ const fixed = viewHeight / ratio;
65
+ return !fixed ? viewWidth : fixed;
66
+ };
67
+ const getFixedHeight = (viewWidth, viewHeight, ratio) => {
68
+ const fixed = viewWidth * ratio;
69
+ return !fixed ? viewHeight : fixed;
70
+ };
52
71
  const Image = forwardRef((props, ref) => {
53
72
  const { src = '', mode = 'scaleToFill', style = {}, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'enable-fast-image': enableFastImage, 'parent-width': parentWidth, 'parent-height': parentHeight, bindload, binderror } = props;
54
73
  const defaultStyle = {
@@ -56,7 +75,6 @@ const Image = forwardRef((props, ref) => {
56
75
  height: DEFAULT_IMAGE_HEIGHT
57
76
  };
58
77
  const styleObj = extendObject({}, defaultStyle, style, { overflow: 'hidden' });
59
- const state = useRef({});
60
78
  const nodeRef = useRef(null);
61
79
  useNodesRef(props, ref, nodeRef, {
62
80
  defaultStyle
@@ -70,13 +88,19 @@ const Image = forwardRef((props, ref) => {
70
88
  const onLayout = ({ nativeEvent: { layout: { width, height } } }) => {
71
89
  state.current.viewWidth = width;
72
90
  state.current.viewHeight = height;
91
+ // 实际渲染尺寸可能会指定的值不一致,误差低于 0.5 则认为没有变化
92
+ if (Math.abs(viewHeight - height) < 0.5 && Math.abs(viewWidth - width) < 0.5) {
93
+ if (state.current.imageWidth && state.current.imageHeight && state.current.ratio) {
94
+ if (!loaded)
95
+ setLoaded(true);
96
+ }
97
+ return;
98
+ }
73
99
  if (state.current.imageWidth && state.current.imageHeight && state.current.ratio) {
74
- setViewWidth(width);
75
- setViewHeight(height);
76
100
  setRatio(state.current.ratio);
77
101
  setImageWidth(state.current.imageWidth);
78
102
  setImageHeight(state.current.imageHeight);
79
- state.current = {};
103
+ setViewSize(state.current.viewWidth, state.current.viewHeight, state.current.ratio);
80
104
  setLoaded(true);
81
105
  }
82
106
  };
@@ -96,43 +120,56 @@ const Image = forwardRef((props, ref) => {
96
120
  const [imageHeight, setImageHeight] = useState(0);
97
121
  const [ratio, setRatio] = useState(0);
98
122
  const [loaded, setLoaded] = useState(!isLayoutMode);
99
- const fixedHeight = useMemo(() => {
100
- const fixed = viewWidth * ratio;
101
- return !fixed ? viewHeight : fixed;
102
- }, [ratio, viewWidth, viewHeight]);
103
- const fixedWidth = useMemo(() => {
104
- if (!ratio)
105
- return viewWidth;
106
- const fixed = viewHeight / ratio;
107
- return !fixed ? viewWidth : fixed;
108
- }, [ratio, viewWidth, viewHeight]);
123
+ const state = useRef({
124
+ viewWidth,
125
+ viewHeight
126
+ });
127
+ function setViewSize(viewWidth, viewHeight, ratio) {
128
+ // 在特定模式下可预测 view 的变化,在onLayout触发时能以此避免重复render
129
+ switch (mode) {
130
+ case 'widthFix': {
131
+ setViewWidth(viewWidth);
132
+ const fixedHeight = getFixedHeight(viewWidth, viewHeight, ratio);
133
+ setViewHeight(fixedHeight);
134
+ break;
135
+ }
136
+ case 'heightFix': {
137
+ setViewHeight(viewHeight);
138
+ const fixedWidth = getFixedWidth(viewWidth, viewHeight, ratio);
139
+ setViewWidth(fixedWidth);
140
+ break;
141
+ }
142
+ default:
143
+ setViewHeight(viewHeight);
144
+ setViewWidth(viewWidth);
145
+ break;
146
+ }
147
+ }
109
148
  const modeStyle = useMemo(() => {
110
149
  if (noMeetCalcRule(isSvg, mode, viewWidth, viewHeight, ratio))
111
150
  return {};
112
151
  switch (mode) {
113
- case 'scaleToFill':
152
+ case 'scaleToFill': // wx 中 svg 图片的 scaleToFill 模式效果与 aspectFit 一致,不会就行图片缩放,此处保持一致
114
153
  case 'aspectFit':
115
154
  if (isSvg) {
116
- const scale = ratio <= 1
117
- ? imageWidth >= viewWidth ? viewWidth / imageWidth : imageWidth / viewWidth
118
- : imageHeight >= viewHeight ? viewHeight / imageHeight : imageHeight / viewHeight;
155
+ const scale = getFitScale(imageWidth, imageHeight, viewWidth, viewHeight);
119
156
  return {
120
157
  transform: [
121
- { scale },
122
- ratio <= 1 ? { translateY: -(imageHeight * scale - viewHeight) / 2 / scale } : { translateX: -(imageWidth * scale - viewWidth) / 2 / scale }
158
+ { translateY: relativeCenteredSize(viewHeight, imageHeight * scale) },
159
+ { translateX: relativeCenteredSize(viewWidth, imageWidth * scale) },
160
+ { scale }
123
161
  ]
124
162
  };
125
163
  }
126
164
  return {};
127
165
  case 'aspectFill':
128
166
  if (isSvg) {
129
- const scale = ratio >= 1
130
- ? imageWidth >= viewWidth ? viewWidth / imageWidth : imageWidth / viewWidth
131
- : imageHeight >= viewHeight ? viewHeight / imageHeight : imageHeight / viewHeight;
167
+ const scale = getFillScale(imageWidth, imageHeight, viewWidth, viewHeight);
132
168
  return {
133
169
  transform: [
134
- { scale },
135
- ratio >= 1 ? { translateY: -(imageHeight * scale - viewHeight) / 2 / scale } : { translateX: -(imageWidth * scale - viewWidth) / 2 / scale }
170
+ { translateY: relativeCenteredSize(viewHeight, imageHeight * scale) },
171
+ { translateX: relativeCenteredSize(viewWidth, imageWidth * scale) },
172
+ { scale }
136
173
  ]
137
174
  };
138
175
  }
@@ -140,9 +177,7 @@ const Image = forwardRef((props, ref) => {
140
177
  case 'widthFix':
141
178
  case 'heightFix':
142
179
  if (isSvg) {
143
- const scale = ratio >= 1
144
- ? imageWidth >= fixedWidth ? fixedWidth / imageWidth : imageWidth / fixedWidth
145
- : imageHeight >= fixedHeight ? fixedHeight / imageHeight : imageHeight / fixedHeight;
180
+ const scale = getFitScale(imageWidth, imageHeight, viewWidth, viewHeight);
146
181
  return {
147
182
  transform: [{ scale }]
148
183
  };
@@ -205,12 +240,23 @@ const Image = forwardRef((props, ref) => {
205
240
  default:
206
241
  return {};
207
242
  }
208
- }, [isSvg, mode, viewWidth, viewHeight, imageWidth, imageHeight, ratio, fixedWidth, fixedHeight]);
243
+ }, [isSvg, mode, viewWidth, viewHeight, imageWidth, imageHeight, ratio]);
209
244
  const onSvgLoad = (evt) => {
210
245
  const { width, height } = evt.nativeEvent.layout;
211
- setRatio(!width ? 0 : height / width);
212
- setImageWidth(width);
246
+ state.current.imageHeight = height;
213
247
  setImageHeight(height);
248
+ state.current.ratio = !width ? 0 : height / width;
249
+ if (isWidthFixMode
250
+ ? state.current.viewWidth
251
+ : isHeightFixMode
252
+ ? state.current.viewHeight
253
+ : state.current.viewWidth && state.current.viewHeight) {
254
+ setRatio(state.current.ratio);
255
+ setImageWidth(width);
256
+ setImageHeight(height);
257
+ setViewSize(state.current.viewWidth, state.current.viewHeight, state.current.ratio);
258
+ setLoaded(true);
259
+ }
214
260
  bindload && bindload(getCustomEvent('load', evt, {
215
261
  detail: { width, height },
216
262
  layoutRef
@@ -248,12 +294,10 @@ const Image = forwardRef((props, ref) => {
248
294
  : isHeightFixMode
249
295
  ? state.current.viewHeight
250
296
  : state.current.viewWidth && state.current.viewHeight) {
251
- state.current.viewWidth && setViewWidth(state.current.viewWidth);
252
- state.current.viewHeight && setViewHeight(state.current.viewHeight);
253
- setRatio(!width ? 0 : height / width);
297
+ setRatio(state.current.ratio);
254
298
  setImageWidth(width);
255
299
  setImageHeight(height);
256
- state.current = {};
300
+ setViewSize(state.current.viewWidth, state.current.viewHeight, state.current.ratio);
257
301
  setLoaded(true);
258
302
  }
259
303
  }, () => {
@@ -263,7 +307,7 @@ const Image = forwardRef((props, ref) => {
263
307
  }, [src, isSvg, isLayoutMode]);
264
308
  const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
265
309
  ref: nodeRef,
266
- style: extendObject({}, normalStyle, layoutStyle, isHeightFixMode ? { width: fixedWidth } : {}, isWidthFixMode ? { height: fixedHeight } : {})
310
+ style: extendObject({}, normalStyle, layoutStyle, isHeightFixMode ? { width: viewWidth } : {}, isWidthFixMode ? { height: viewHeight } : {})
267
311
  }), [
268
312
  'src',
269
313
  'mode',
@@ -1,6 +1,6 @@
1
- import React, { useContext, useEffect } from 'react';
1
+ import React, { useContext, useEffect, useRef } from 'react';
2
2
  import { Keyboard, View } from 'react-native';
3
- import Animated, { useSharedValue, useAnimatedStyle, withTiming, Easing } from 'react-native-reanimated';
3
+ import Animated, { useSharedValue, useAnimatedStyle, withTiming, Easing, cancelAnimation } from 'react-native-reanimated';
4
4
  import { KeyboardAvoidContext } from './context';
5
5
  import { isIOS } from './utils';
6
6
  const KeyboardAvoidingView = ({ children, style, contentContainerStyle }) => {
@@ -9,14 +9,23 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }) => {
9
9
  const offset = useSharedValue(0);
10
10
  const basic = useSharedValue('auto');
11
11
  const keyboardAvoid = useContext(KeyboardAvoidContext);
12
+ // fix: 某些特殊机型下隐藏键盘可能会先触发一次 keyboardWillShow,
13
+ // 比如机型 iPhone 11 Pro,可能会导致显隐动画冲突
14
+ // 因此增加状态标记 + cancelAnimation 来优化
15
+ const isShow = useRef(false);
12
16
  const animatedStyle = useAnimatedStyle(() => ({
13
17
  transform: [{ translateY: -offset.value }],
14
18
  flexBasis: basic.value
15
19
  }));
16
20
  const resetKeyboard = () => {
21
+ if (!isShow.current) {
22
+ return;
23
+ }
24
+ isShow.current = false;
17
25
  if (keyboardAvoid?.current) {
18
26
  keyboardAvoid.current = null;
19
27
  }
28
+ cancelAnimation(offset);
20
29
  offset.value = withTiming(0, { duration, easing });
21
30
  basic.value = 'auto';
22
31
  };
@@ -30,8 +39,10 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }) => {
30
39
  if (isIOS) {
31
40
  subscriptions = [
32
41
  Keyboard.addListener('keyboardWillShow', (evt) => {
33
- if (!keyboardAvoid?.current)
42
+ if (!keyboardAvoid?.current || isShow.current) {
34
43
  return;
44
+ }
45
+ isShow.current = true;
35
46
  const { endCoordinates } = evt;
36
47
  const { ref, cursorSpacing = 0 } = keyboardAvoid.current;
37
48
  setTimeout(() => {
@@ -40,6 +51,7 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }) => {
40
51
  const aboveValue = -aboveOffset >= cursorSpacing ? 0 : aboveOffset + cursorSpacing;
41
52
  const belowValue = Math.min(endCoordinates.height, aboveOffset + cursorSpacing);
42
53
  const value = aboveOffset > 0 ? belowValue : aboveValue;
54
+ cancelAnimation(offset);
43
55
  offset.value = withTiming(value, { duration, easing }, (finished) => {
44
56
  if (finished) {
45
57
  // Set flexBasic after animation to trigger re-layout and reset layout information
@@ -55,8 +67,10 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }) => {
55
67
  else {
56
68
  subscriptions = [
57
69
  Keyboard.addListener('keyboardDidShow', (evt) => {
58
- if (!keyboardAvoid?.current)
70
+ if (!keyboardAvoid?.current || isShow.current) {
59
71
  return;
72
+ }
73
+ isShow.current = true;
60
74
  const { endCoordinates } = evt;
61
75
  const { ref, cursorSpacing = 0 } = keyboardAvoid.current;
62
76
  ref?.current?.measure((x, y, width, height, pageX, pageY) => {
@@ -65,6 +79,7 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }) => {
65
79
  const aboveValue = -aboveOffset >= cursorSpacing ? 0 : aboveOffset + cursorSpacing;
66
80
  const belowValue = Math.min(belowOffset, cursorSpacing);
67
81
  const value = aboveOffset > 0 ? belowValue : aboveValue;
82
+ cancelAnimation(offset);
68
83
  offset.value = withTiming(value, { duration, easing }, (finished) => {
69
84
  if (finished) {
70
85
  // Set flexBasic after animation to trigger re-layout and reset layout information
@@ -17,7 +17,7 @@ const styles = {
17
17
  };
18
18
  const DefaultPickerItemH = 36;
19
19
  const _PickerView = forwardRef((props, ref) => {
20
- const { children, value = [], bindchange, style, 'indicator-style': indicatorStyle = {}, 'mask-style': pickerMaskStyle = {}, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
20
+ const { children, value = [], bindchange, style, 'enable-wheel-animation': enableWheelAnimation = true, 'indicator-style': indicatorStyle = {}, 'mask-style': pickerMaskStyle = {}, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
21
21
  const { height: indicatorH, ...pickerIndicatorStyle } = indicatorStyle;
22
22
  const nodeRef = useRef(null);
23
23
  const cloneRef = useRef(null);
@@ -75,7 +75,8 @@ const _PickerView = forwardRef((props, ref) => {
75
75
  onSelectChange: onSelectChange.bind(null, index),
76
76
  initialIndex,
77
77
  pickerIndicatorStyle,
78
- pickerMaskStyle
78
+ pickerMaskStyle,
79
+ enableWheelAnimation
79
80
  });
80
81
  const realElement = React.cloneElement(child, wrappedProps);
81
82
  return wrapChildren({
@@ -5,12 +5,13 @@ import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAn
5
5
  import useNodesRef from '../useNodesRef';
6
6
  import PickerIndicator from './pickerViewIndicator';
7
7
  import PickerMask from './pickerViewMask';
8
- import MpxPickerVIewColumnItem from './pickerViewColumnItem';
8
+ import MpxPickerViewColumnItem from './pickerViewColumnItem';
9
+ import MpxPickerViewColumnItemLite from './pickerViewColumnItemLite';
9
10
  import { PickerViewColumnAnimationContext } from '../mpx-picker-view/pickerVIewContext';
10
11
  import { calcHeightOffsets } from './pickerViewFaces';
11
12
  const visibleCount = 5;
12
13
  const _PickerViewColumn = forwardRef((props, ref) => {
13
- const { columnData, columnIndex, initialIndex, onSelectChange, style, wrapperStyle, pickerMaskStyle, pickerIndicatorStyle, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
14
+ const { columnData, columnIndex, initialIndex, onSelectChange, style, wrapperStyle, pickerMaskStyle, pickerIndicatorStyle, enableWheelAnimation = true, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
14
15
  const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext });
15
16
  const { textStyle = {} } = splitStyle(normalStyle);
16
17
  const { textProps = {} } = splitProps(props);
@@ -217,7 +218,9 @@ const _PickerViewColumn = forwardRef((props, ref) => {
217
218
  }
218
219
  }, [itemRawH, maxIndex, calcOffset, onMomentumScrollEnd]);
219
220
  const renderInnerchild = () => columnData.map((item, index) => {
220
- return (<MpxPickerVIewColumnItem key={index} item={item} index={index} itemHeight={itemHeight} textStyle={textStyle} textProps={textProps} visibleCount={visibleCount} onItemLayout={onItemLayout}/>);
221
+ return enableWheelAnimation
222
+ ? (<MpxPickerViewColumnItem key={index} item={item} index={index} itemHeight={itemHeight} textStyle={textStyle} textProps={textProps} visibleCount={visibleCount} onItemLayout={onItemLayout}/>)
223
+ : (<MpxPickerViewColumnItemLite key={index} item={item} index={index} itemHeight={itemHeight} textStyle={textStyle} textProps={textProps} onItemLayout={onItemLayout}/>);
221
224
  });
222
225
  const renderScollView = () => {
223
226
  const innerProps = extendObject({}, layoutProps, {
@@ -246,9 +249,9 @@ const _PickerViewColumn = forwardRef((props, ref) => {
246
249
  const renderIndicator = () => (<PickerIndicator itemHeight={itemHeight} indicatorItemStyle={pickerIndicatorStyle}/>);
247
250
  const renderMask = () => (<PickerMask itemHeight={itemHeight} maskContainerStyle={pickerMaskStyle}/>);
248
251
  return (<View style={[styles.wrapper, normalStyle]}>
249
- {renderScollView()}
250
- {renderMask()}
251
- {renderIndicator()}
252
+ {renderScollView()}
253
+ {renderMask()}
254
+ {renderIndicator()}
252
255
  </View>);
253
256
  });
254
257
  const styles = StyleSheet.create({
@@ -1,23 +1,20 @@
1
- import React, { useEffect } from 'react';
2
- import Reanimated, { Extrapolation, interpolate, useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
1
+ import React, { useMemo } from 'react';
2
+ import Reanimated, { Extrapolation, interpolate, useAnimatedStyle } from 'react-native-reanimated';
3
3
  import { extendObject } from '../utils';
4
4
  import { createFaces } from './pickerViewFaces';
5
5
  import { usePickerViewColumnAnimationContext, usePickerViewStyleContext } from '../mpx-picker-view/pickerVIewContext';
6
6
  const PickerViewColumnItem = ({ item, index, itemHeight, itemWidth = '100%', textStyle, textProps, visibleCount, onItemLayout }) => {
7
7
  const textStyleFromAncestor = usePickerViewStyleContext();
8
8
  const offsetYShared = usePickerViewColumnAnimationContext();
9
- const facesShared = useSharedValue(createFaces(itemHeight, visibleCount));
10
- useEffect(() => {
11
- facesShared.value = createFaces(itemHeight, visibleCount);
12
- }, [itemHeight]);
9
+ const facesShared = useMemo(() => createFaces(itemHeight, visibleCount), [itemHeight, visibleCount]);
13
10
  const animatedStyles = useAnimatedStyle(() => {
14
- const inputRange = facesShared.value.map((f) => itemHeight * (index + f.index));
11
+ const inputRange = facesShared.map((f) => itemHeight * (index + f.index));
15
12
  return {
16
- opacity: interpolate(offsetYShared.value, inputRange, facesShared.value.map((x) => x.opacity), Extrapolation.CLAMP),
13
+ opacity: interpolate(offsetYShared.value, inputRange, facesShared.map((x) => x.opacity), Extrapolation.CLAMP),
17
14
  transform: [
18
- { translateY: interpolate(offsetYShared.value, inputRange, facesShared.value.map((x) => x.offsetY), Extrapolation.EXTEND) },
19
- { rotateX: interpolate(offsetYShared.value, inputRange, facesShared.value.map((x) => x.deg), Extrapolation.CLAMP) + 'deg' },
20
- { scale: interpolate(offsetYShared.value, inputRange, facesShared.value.map((x) => x.scale), Extrapolation.EXTEND) }
15
+ { translateY: interpolate(offsetYShared.value, inputRange, facesShared.map((x) => x.offsetY), Extrapolation.EXTEND) },
16
+ { rotateX: interpolate(offsetYShared.value, inputRange, facesShared.map((x) => x.deg), Extrapolation.CLAMP) + 'deg' },
17
+ { scale: interpolate(offsetYShared.value, inputRange, facesShared.map((x) => x.scale), Extrapolation.EXTEND) }
21
18
  ]
22
19
  };
23
20
  });
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { View } from 'react-native';
3
+ import { extendObject } from '../utils';
4
+ import { usePickerViewStyleContext } from '../mpx-picker-view/pickerVIewContext';
5
+ const PickerViewColumnItem = ({ item, index, itemHeight, itemWidth = '100%', textStyle, textProps, onItemLayout }) => {
6
+ const textStyleFromAncestor = usePickerViewStyleContext();
7
+ const strKey = `picker-column-item-${index}`;
8
+ const restProps = index === 0 ? { onLayout: onItemLayout } : {};
9
+ const itemProps = extendObject({
10
+ style: extendObject({ height: itemHeight, width: '100%' }, textStyleFromAncestor, textStyle, item.props.style)
11
+ }, textProps, restProps);
12
+ const realItem = React.cloneElement(item, itemProps);
13
+ return (<View key={strKey} style={[
14
+ { height: itemHeight, width: itemWidth, pointerEvents: 'none' }
15
+ ]}>
16
+ {realItem}
17
+ </View>);
18
+ };
19
+ PickerViewColumnItem.displayName = 'MpxPickerViewColumnItem';
20
+ export default PickerViewColumnItem;
@@ -1,14 +1,18 @@
1
1
  import { useContext, useEffect, useRef } from 'react';
2
- import { PortalContext, RouteContext, VarContext } from '../context';
2
+ import { PortalContext, ProviderContext, RouteContext, VarContext } from '../context';
3
3
  import PortalHost, { portal } from './portal-host';
4
4
  const Portal = ({ children }) => {
5
5
  const manager = useContext(PortalContext);
6
6
  const keyRef = useRef(null);
7
7
  const { pageId } = useContext(RouteContext) || {};
8
8
  const varContext = useContext(VarContext);
9
+ const parentProvides = useContext(ProviderContext);
9
10
  if (varContext) {
10
11
  children = (<VarContext.Provider value={varContext} key='varContextWrap'>{children}</VarContext.Provider>);
11
12
  }
13
+ if (parentProvides) {
14
+ children = (<ProviderContext.Provider value={parentProvides} key='providerContextWrap'>{children}</ProviderContext.Provider>);
15
+ }
12
16
  useEffect(() => {
13
17
  manager.update(keyRef.current, children);
14
18
  }, [children]);
@@ -48,8 +48,6 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
48
48
  const scrollOffset = useRef(new RNAnimated.Value(0)).current;
49
49
  const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
50
50
  const waitForHandlers = flatGesture(waitFor);
51
- const snapScrollTop = useRef(0);
52
- const snapScrollLeft = useRef(0);
53
51
  const [refreshing, setRefreshing] = useState(false);
54
52
  const [enableScroll, setEnableScroll] = useState(true);
55
53
  const enableScrollValue = useSharedValue(true);
@@ -127,14 +125,12 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
127
125
  warn('scroll-x and scroll-y cannot be set to true at the same time, Mpx will use the value of scroll-y as the criterion');
128
126
  }
129
127
  useEffect(() => {
130
- if (snapScrollTop.current !== scrollTop || snapScrollLeft.current !== scrollLeft) {
131
- initialTimeout.current = setTimeout(() => {
132
- scrollToOffset(scrollLeft, scrollTop);
133
- }, 0);
134
- return () => {
135
- initialTimeout.current && clearTimeout(initialTimeout.current);
136
- };
137
- }
128
+ initialTimeout.current = setTimeout(() => {
129
+ scrollToOffset(scrollLeft, scrollTop);
130
+ }, 0);
131
+ return () => {
132
+ initialTimeout.current && clearTimeout(initialTimeout.current);
133
+ };
138
134
  }, [scrollTop, scrollLeft]);
139
135
  useEffect(() => {
140
136
  if (scrollIntoView && __selectRef) {
@@ -316,10 +312,6 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
316
312
  function scrollToOffset(x = 0, y = 0, animated = scrollWithAnimation) {
317
313
  if (scrollViewRef.current) {
318
314
  scrollViewRef.current.scrollTo({ x, y, animated });
319
- scrollOptions.current.scrollLeft = x;
320
- scrollOptions.current.scrollTop = y;
321
- snapScrollLeft.current = x;
322
- snapScrollTop.current = y;
323
315
  }
324
316
  }
325
317
  function onScrollTouchMove(e) {
@@ -1,16 +1,40 @@
1
1
  /**
2
2
  * ✔ selectable
3
3
  * ✘ space
4
- * decode
4
+ * decode
5
5
  */
6
6
  import { Text } from 'react-native';
7
- import { useRef, forwardRef, createElement } from 'react';
7
+ import { useRef, forwardRef, createElement, Children } from 'react';
8
8
  import Portal from './mpx-portal';
9
9
  import useInnerProps from './getInnerListeners';
10
10
  import useNodesRef from './useNodesRef'; // 引入辅助函数
11
11
  import { useTransformStyle, wrapChildren, extendObject } from './utils';
12
+ const decodeMap = {
13
+ '&lt;': '<',
14
+ '&gt;': '>',
15
+ '&quot;': '"',
16
+ '&amp;': '&',
17
+ '&#39;': '\'',
18
+ '&nbsp;': ' '
19
+ };
20
+ const encodedRe = /&(?:lt|gt|quot|amp|#39|nbsp);/g;
21
+ function decode(value) {
22
+ if (value != null) {
23
+ return value.replace(encodedRe, function (match) {
24
+ return decodeMap[match];
25
+ });
26
+ }
27
+ }
28
+ function getDecodedChildren(children) {
29
+ return Children.map(children, (child) => {
30
+ if (typeof child === 'string') {
31
+ return decode(child);
32
+ }
33
+ return child;
34
+ });
35
+ }
12
36
  const _Text = forwardRef((props, ref) => {
13
- const { style = {}, allowFontScaling = false, selectable, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'user-select': userSelect, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight } = props;
37
+ const { style = {}, allowFontScaling = false, selectable, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'user-select': userSelect, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, decode } = props;
14
38
  const { normalStyle, hasVarDec, varContextRef, hasPositionFixed } = useTransformStyle(style, {
15
39
  enableVar,
16
40
  externalVarContext,
@@ -28,9 +52,13 @@ const _Text = forwardRef((props, ref) => {
28
52
  selectable: !!selectable || !!userSelect,
29
53
  allowFontScaling
30
54
  }), [
31
- 'user-select'
55
+ 'user-select',
56
+ 'decode'
32
57
  ]);
33
- let finalComponent = createElement(Text, innerProps, wrapChildren(props, {
58
+ const children = decode ? getDecodedChildren(props.children) : props.children;
59
+ let finalComponent = createElement(Text, innerProps, wrapChildren(extendObject({}, props, {
60
+ children
61
+ }), {
34
62
  hasVarDec,
35
63
  varContext: varContextRef.current
36
64
  }));
@@ -398,7 +398,7 @@ function parseLinearGradient(text) {
398
398
  });
399
399
  }
400
400
  function parseBgImage(text) {
401
- if (!text)
401
+ if (!text || text === 'none')
402
402
  return {};
403
403
  const src = parseUrl(text);
404
404
  if (src)
@@ -176,7 +176,7 @@ const _WebView = forwardRef((props, ref) => {
176
176
  }
177
177
  break;
178
178
  case 'postMessage':
179
- bindmessage && bindmessage(getCustomEvent('messsage', {}, {
179
+ bindmessage && bindmessage(getCustomEvent('message', {}, {
180
180
  detail: {
181
181
  data: params[0]?.data
182
182
  }
@@ -169,24 +169,34 @@ function transformPercent(styleObj, percentKeyPaths, percentConfig) {
169
169
  function resolveVar(input, varContext) {
170
170
  const parsed = parseFunc(input, 'var');
171
171
  const replaced = new ReplaceSource(input);
172
- parsed.forEach(({ start, end, args }) => {
172
+ for (const { start, end, args } of parsed) {
173
173
  const varName = args[0];
174
- const fallback = args[1] || '';
174
+ const fallback = args[1];
175
175
  let varValue = hasOwn(varContext, varName) ? varContext[varName] : fallback;
176
+ if (varValue === undefined)
177
+ return;
176
178
  if (varUseRegExp.test(varValue)) {
177
- varValue = '' + resolveVar(varValue, varContext);
179
+ varValue = resolveVar(varValue, varContext);
180
+ if (varValue === undefined)
181
+ return;
178
182
  }
179
183
  else {
180
- varValue = '' + global.__formatValue(varValue);
184
+ varValue = global.__formatValue(varValue);
181
185
  }
182
186
  replaced.replace(start, end - 1, varValue);
183
- });
187
+ }
184
188
  return global.__formatValue(replaced.source());
185
189
  }
186
190
  function transformVar(styleObj, varKeyPaths, varContext, visitOther) {
187
191
  varKeyPaths.forEach((varKeyPath) => {
188
192
  setStyle(styleObj, varKeyPath, ({ target, key, value }) => {
189
- target[key] = resolveVar(value, varContext);
193
+ const resolved = resolveVar(value, varContext);
194
+ if (resolved === undefined) {
195
+ delete target[key];
196
+ error(`Can not resolve css var at ${varKeyPath.join('.')}:${value}.`);
197
+ return;
198
+ }
199
+ target[key] = resolved;
190
200
  visitOther({ target, key, value: target[key], keyPath: varKeyPath });
191
201
  });
192
202
  });