@mpxjs/webpack-plugin 2.9.69 → 2.9.70-alpha.1

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 (144) hide show
  1. package/README.md +1 -1
  2. package/lib/config.js +14 -0
  3. package/lib/dependencies/AddEntryDependency.js +24 -0
  4. package/lib/dependencies/ResolveDependency.js +5 -0
  5. package/lib/index.js +38 -7
  6. package/lib/json-compiler/helper.js +3 -3
  7. package/lib/loader.js +52 -0
  8. package/lib/platform/template/wx/component-config/button.js +14 -2
  9. package/lib/platform/template/wx/component-config/image.js +4 -0
  10. package/lib/platform/template/wx/component-config/input.js +5 -1
  11. package/lib/platform/template/wx/component-config/rich-text.js +4 -0
  12. package/lib/platform/template/wx/component-config/scroll-view.js +4 -0
  13. package/lib/platform/template/wx/component-config/swiper.js +1 -1
  14. package/lib/platform/template/wx/component-config/switch.js +4 -0
  15. package/lib/platform/template/wx/component-config/text.js +4 -0
  16. package/lib/platform/template/wx/component-config/textarea.js +6 -1
  17. package/lib/platform/template/wx/component-config/view.js +4 -0
  18. package/lib/platform/template/wx/index.js +127 -1
  19. package/lib/react/processTemplate.js +3 -0
  20. package/lib/resolve-loader.js +4 -1
  21. package/lib/runtime/components/react/context.ts +4 -0
  22. package/lib/runtime/components/react/dist/context.js +5 -0
  23. package/lib/runtime/components/react/dist/event.config.js +24 -24
  24. package/lib/runtime/components/react/dist/getInnerListeners.js +183 -166
  25. package/lib/runtime/components/react/dist/locale-provider.jsx +15 -0
  26. package/lib/runtime/components/react/dist/mpx-button.jsx +39 -74
  27. package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +30 -12
  28. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +13 -19
  29. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +29 -38
  30. package/lib/runtime/components/react/dist/mpx-form.jsx +16 -19
  31. package/lib/runtime/components/react/dist/mpx-icon.jsx +8 -16
  32. package/lib/runtime/components/react/dist/mpx-image.jsx +295 -0
  33. package/lib/runtime/components/react/dist/mpx-input.jsx +54 -27
  34. package/lib/runtime/components/react/dist/mpx-label.jsx +15 -22
  35. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +13 -16
  36. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +14 -14
  37. package/lib/runtime/components/react/dist/mpx-navigator.jsx +2 -4
  38. package/lib/runtime/components/react/dist/mpx-picker/date.jsx +6 -2
  39. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +5 -3
  40. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +6 -2
  41. package/lib/runtime/components/react/dist/mpx-picker/region.jsx +6 -2
  42. package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +6 -2
  43. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +10 -14
  44. package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +39 -0
  45. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +126 -112
  46. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +32 -29
  47. package/lib/runtime/components/react/dist/mpx-portal/portal-consumer.jsx +23 -0
  48. package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +124 -0
  49. package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +40 -0
  50. package/lib/runtime/components/react/dist/mpx-portal.jsx +12 -0
  51. package/lib/runtime/components/react/dist/mpx-provider.jsx +31 -0
  52. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +11 -19
  53. package/lib/runtime/components/react/dist/mpx-radio.jsx +27 -42
  54. package/lib/runtime/components/react/dist/mpx-rich-text/html.js +39 -0
  55. package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +62 -0
  56. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +7 -5
  57. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +62 -47
  58. package/lib/runtime/components/react/dist/mpx-simple-text.jsx +11 -0
  59. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +28 -9
  60. package/lib/runtime/components/react/dist/mpx-swiper.jsx +613 -0
  61. package/lib/runtime/components/react/dist/mpx-switch.jsx +20 -10
  62. package/lib/runtime/components/react/dist/mpx-text.jsx +11 -10
  63. package/lib/runtime/components/react/dist/mpx-textarea.jsx +8 -3
  64. package/lib/runtime/components/react/dist/mpx-view.jsx +37 -89
  65. package/lib/runtime/components/react/dist/mpx-web-view.jsx +205 -46
  66. package/lib/runtime/components/react/dist/pickerFaces.js +12 -6
  67. package/lib/runtime/components/react/dist/pickerVIewContext.js +9 -0
  68. package/lib/runtime/components/react/dist/pickerViewMask.jsx +18 -0
  69. package/lib/runtime/components/react/dist/{pickerOverlay.jsx → pickerViewOverlay.jsx} +5 -3
  70. package/lib/runtime/components/react/dist/useAnimationHooks.js +50 -12
  71. package/lib/runtime/components/react/dist/utils.jsx +83 -28
  72. package/lib/runtime/components/react/getInnerListeners.ts +35 -28
  73. package/lib/runtime/components/react/mpx-button.tsx +55 -36
  74. package/lib/runtime/components/react/mpx-canvas/index.tsx +2 -2
  75. package/lib/runtime/components/react/mpx-checkbox-group.tsx +13 -12
  76. package/lib/runtime/components/react/mpx-checkbox.tsx +28 -28
  77. package/lib/runtime/components/react/mpx-form.tsx +10 -8
  78. package/lib/runtime/components/react/mpx-icon.tsx +10 -15
  79. package/lib/runtime/components/react/mpx-image.tsx +396 -0
  80. package/lib/runtime/components/react/mpx-input.tsx +61 -33
  81. package/lib/runtime/components/react/mpx-label.tsx +14 -13
  82. package/lib/runtime/components/react/mpx-movable-area.tsx +8 -7
  83. package/lib/runtime/components/react/mpx-movable-view.tsx +1 -1
  84. package/lib/runtime/components/react/mpx-picker/date.tsx +5 -2
  85. package/lib/runtime/components/react/mpx-picker/index.tsx +3 -2
  86. package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +5 -2
  87. package/lib/runtime/components/react/mpx-picker/region.tsx +5 -2
  88. package/lib/runtime/components/react/mpx-picker/selector.tsx +5 -2
  89. package/lib/runtime/components/react/mpx-picker/time.tsx +10 -15
  90. package/lib/runtime/components/react/mpx-picker/type.ts +48 -43
  91. package/lib/runtime/components/react/mpx-picker-view-column.tsx +4 -1
  92. package/lib/runtime/components/react/mpx-picker-view.tsx +7 -1
  93. package/lib/runtime/components/react/mpx-radio-group.tsx +11 -12
  94. package/lib/runtime/components/react/mpx-radio.tsx +26 -29
  95. package/lib/runtime/components/react/mpx-scroll-view.tsx +32 -30
  96. package/lib/runtime/components/react/mpx-simple-text.tsx +18 -0
  97. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +4 -2
  98. package/lib/runtime/components/react/mpx-swiper-item.tsx +3 -2
  99. package/lib/runtime/components/react/mpx-switch.tsx +10 -8
  100. package/lib/runtime/components/react/mpx-text.tsx +6 -2
  101. package/lib/runtime/components/react/mpx-view.tsx +37 -45
  102. package/lib/runtime/components/react/mpx-web-view.tsx +25 -15
  103. package/lib/runtime/components/react/types/global.d.ts +1 -16
  104. package/lib/runtime/components/react/utils.tsx +24 -24
  105. package/lib/runtime/components/tenon/getInnerListeners.js +334 -0
  106. package/lib/runtime/components/tenon/tenon-button.vue +309 -0
  107. package/lib/runtime/components/tenon/tenon-image.vue +66 -0
  108. package/lib/runtime/components/tenon/tenon-input.vue +171 -0
  109. package/lib/runtime/components/tenon/tenon-rich-text.vue +26 -0
  110. package/lib/runtime/components/tenon/tenon-scroll-view.vue +127 -0
  111. package/lib/runtime/components/tenon/tenon-switch.vue +96 -0
  112. package/lib/runtime/components/tenon/tenon-text.vue +70 -0
  113. package/lib/runtime/components/tenon/tenon-textarea.vue +86 -0
  114. package/lib/runtime/components/tenon/tenon-view.vue +93 -0
  115. package/lib/runtime/components/web/getInnerListeners.js +6 -6
  116. package/lib/runtime/components/web/mpx-movable-view.vue +334 -344
  117. package/lib/runtime/components/web/mpx-picker-view-column.vue +75 -75
  118. package/lib/runtime/components/web/mpx-picker.vue +382 -385
  119. package/lib/runtime/components/web/mpx-web-view.vue +162 -162
  120. package/lib/runtime/optionProcessor.js +7 -16
  121. package/lib/runtime/optionProcessor.tenon.js +84 -0
  122. package/lib/runtime/utils.js +2 -0
  123. package/lib/style-compiler/index.js +1 -1
  124. package/lib/style-compiler/plugins/hm.js +20 -0
  125. package/lib/template-compiler/bind-this.js +7 -2
  126. package/lib/template-compiler/compiler.js +67 -40
  127. package/lib/template-compiler/gen-node-react.js +2 -2
  128. package/lib/tenon/index.js +112 -0
  129. package/lib/tenon/processJSON.js +352 -0
  130. package/lib/tenon/processScript.js +198 -0
  131. package/lib/tenon/processStyles.js +21 -0
  132. package/lib/tenon/processTemplate.js +125 -0
  133. package/lib/tenon/script-helper.js +223 -0
  134. package/lib/utils/env.js +6 -1
  135. package/lib/utils/get-relative-path.js +25 -0
  136. package/package.json +7 -3
  137. package/LICENSE +0 -433
  138. package/lib/runtime/components/react/dist/mpx-image/index.jsx +0 -226
  139. package/lib/runtime/components/react/dist/mpx-image/svg.jsx +0 -7
  140. package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +0 -478
  141. package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +0 -68
  142. package/lib/runtime/components/react/dist/mpx-swiper/type.js +0 -1
  143. package/lib/runtime/components/react/mpx-image/index.tsx +0 -345
  144. package/lib/runtime/components/react/mpx-image/svg.tsx +0 -22
@@ -28,10 +28,12 @@ import { FormContext } from '../context';
28
28
  * ✘ bindcolumnchange
29
29
  */
30
30
  const _Picker = forwardRef((props, ref) => {
31
- const { mode = 'selector', value, bindcancel, bindchange, children, bindcolumnchange } = props;
31
+ const { mode = 'selector', value, bindcancel, bindchange, children, bindcolumnchange, style } = props;
32
32
  const innerLayout = useRef({});
33
33
  const nodeRef = useRef(null);
34
- useNodesRef(props, ref, nodeRef, {});
34
+ useNodesRef(props, ref, nodeRef, {
35
+ style
36
+ });
35
37
  const innerProps = useInnerProps(props, {
36
38
  ref: nodeRef
37
39
  }, [], { layoutRef: innerLayout });
@@ -78,7 +80,7 @@ const _Picker = forwardRef((props, ref) => {
78
80
  bindcolumnchange && bindcolumnchange(eventData);
79
81
  };
80
82
  const commonProps = {
81
- ...{ innerProps },
83
+ ...innerProps,
82
84
  mode,
83
85
  children,
84
86
  bindchange: onChange,
@@ -77,7 +77,7 @@ function getColumnIndexByValue(range = [], column, value = []) {
77
77
  return changeIndex;
78
78
  }
79
79
  const _MultiSelectorPicker = forwardRef((props, ref) => {
80
- const { range, value, disabled, bindchange, bindcancel, children, bindcolumnchange } = props;
80
+ const { range, value, disabled, bindchange, bindcancel, children, bindcolumnchange, style } = props;
81
81
  const formatRange = formatRangeFun(range, props['range-key']);
82
82
  const initValue = getInnerValueByIndex(formatRange, value);
83
83
  // 选中的索引值
@@ -87,7 +87,10 @@ const _MultiSelectorPicker = forwardRef((props, ref) => {
87
87
  // 存储layout布局信息
88
88
  const layoutRef = useRef({});
89
89
  const viewRef = useRef(null);
90
- useNodesRef(props, ref, viewRef, {});
90
+ const nodeRef = useRef(null);
91
+ useNodesRef(props, ref, nodeRef, {
92
+ style
93
+ });
91
94
  useEffect(() => {
92
95
  if (range) {
93
96
  const newFormatRange = formatRangeFun(range, props['range-key']);
@@ -117,6 +120,7 @@ const _MultiSelectorPicker = forwardRef((props, ref) => {
117
120
  });
118
121
  };
119
122
  const antPickerProps = {
123
+ ref: nodeRef,
120
124
  data,
121
125
  value: selected,
122
126
  cols: range.length,
@@ -35,13 +35,16 @@ function formateRegionData(clObj = [], customItem, depth = 2) {
35
35
  return obj;
36
36
  }
37
37
  const _RegionPicker = forwardRef((props, ref) => {
38
- const { children, value, bindchange, bindcancel, disabled } = props;
38
+ const { children, value, bindchange, bindcancel, disabled, style } = props;
39
39
  const formatRegionData = formateRegionData(regionData, props['custom-item']);
40
40
  const [regionvalue, setRegionValue] = useState(value);
41
41
  // 存储layout布局信息
42
42
  const layoutRef = useRef({});
43
43
  const viewRef = useRef(null);
44
- useNodesRef(props, ref, viewRef, {});
44
+ const nodeRef = useRef(null);
45
+ useNodesRef(props, ref, nodeRef, {
46
+ style
47
+ });
45
48
  const onChange = (value) => {
46
49
  // 通过 value 查找 code
47
50
  let tmp = regionData;
@@ -75,6 +78,7 @@ const _RegionPicker = forwardRef((props, ref) => {
75
78
  bindcancel && bindcancel();
76
79
  };
77
80
  const regionProps = {
81
+ ref: nodeRef,
78
82
  data: formatRegionData,
79
83
  value: regionvalue,
80
84
  onChange,
@@ -18,7 +18,7 @@ const formatRangeFun = (range, rangeKey = '') => {
18
18
  return newRange;
19
19
  };
20
20
  const _SelectorPicker = forwardRef((props, ref) => {
21
- const { range, children, value, disabled, bindchange, bindcancel } = props;
21
+ const { range, children, value, disabled, bindchange, bindcancel, style } = props;
22
22
  // 格式化数据为Array<*>
23
23
  const formatRange = formatRangeFun(range, props['range-key']);
24
24
  // 选中的索引值
@@ -28,7 +28,10 @@ const _SelectorPicker = forwardRef((props, ref) => {
28
28
  // 存储layout布局信息
29
29
  const layoutRef = useRef({});
30
30
  const viewRef = useRef(null);
31
- useNodesRef(props, ref, viewRef, {});
31
+ const nodeRef = useRef(null);
32
+ useNodesRef(props, ref, nodeRef, {
33
+ style
34
+ });
32
35
  useEffect(() => {
33
36
  if (range) {
34
37
  const newFormatRange = formatRangeFun(range, props['range-key']);
@@ -53,6 +56,7 @@ const _SelectorPicker = forwardRef((props, ref) => {
53
56
  });
54
57
  };
55
58
  const antPickerProps = {
59
+ ref: nodeRef,
56
60
  data,
57
61
  value: [selected],
58
62
  cols: 1,
@@ -1,4 +1,5 @@
1
1
  import { View, Text, Modal, TouchableWithoutFeedback } from 'react-native';
2
+ import Portal from '../mpx-portal';
2
3
  import { PickerView } from '@ant-design/react-native';
3
4
  import React, { forwardRef, useState, useRef, useEffect } from 'react';
4
5
  import useNodesRef from '../useNodesRef'; // 引入辅助函数
@@ -11,8 +12,8 @@ const styles = {
11
12
  showModal: {
12
13
  backgroundColor: 'black',
13
14
  opacity: 0.5,
14
- position: 'absolute',
15
- width: '100%'
15
+ width: '100%',
16
+ height: '100%'
16
17
  },
17
18
  hideModal: {
18
19
  opacity: 1,
@@ -117,7 +118,7 @@ function checkSelectedIsValid(strStart, strEnd, selected) {
117
118
  */
118
119
  // start="02:10" end = 23:01
119
120
  const _TimePicker = forwardRef((props, ref) => {
120
- const { children, start, end, value, bindchange, bindcancel, disabled } = props;
121
+ const { children, start, end, value, bindchange, bindcancel, style } = props;
121
122
  const defaultProps = {
122
123
  start: '00:10',
123
124
  end: '23:59'
@@ -127,11 +128,11 @@ const _TimePicker = forwardRef((props, ref) => {
127
128
  // 存储layout布局信息
128
129
  const layoutRef = useRef({});
129
130
  const viewRef = useRef(null);
130
- useNodesRef(props, ref, viewRef, {});
131
+ const nodeRef = useRef(null);
132
+ useNodesRef(props, ref, nodeRef, { style });
131
133
  // 存储modal的布局信息
132
134
  const modalLayoutRef = useRef({});
133
135
  const modalRef = useRef(null);
134
- useNodesRef(props, ref, modalRef, {});
135
136
  const [visible, setVisible] = useState(false);
136
137
  const columnData = generateColumns();
137
138
  const [data, setData] = useState(columnData);
@@ -175,12 +176,6 @@ const _TimePicker = forwardRef((props, ref) => {
175
176
  else {
176
177
  // [9, 13]
177
178
  setTimeValue(date);
178
- const strDate = formatStr(date);
179
- bindchange && bindchange({
180
- detail: {
181
- value: strDate
182
- }
183
- });
184
179
  }
185
180
  };
186
181
  const onElementLayout = () => {
@@ -197,6 +192,7 @@ const _TimePicker = forwardRef((props, ref) => {
197
192
  };
198
193
  const renderModalChildren = () => {
199
194
  const pickerProps = {
195
+ ref: nodeRef,
200
196
  data,
201
197
  value: timevalue,
202
198
  defaultValue: timevalue,
@@ -230,15 +226,15 @@ const _TimePicker = forwardRef((props, ref) => {
230
226
  </TouchableWithoutFeedback>
231
227
  </View>;
232
228
  };
233
- const strStyle = visible ? styles.showModal : styles.hideModal;
234
- const mheight = Math.floor(offsetTop);
235
229
  // Animated.View
236
230
  return (<>
237
- <View style={{ ...strStyle, height: visible ? mheight : 0, bottom: 0 }}>
231
+ <Portal>
232
+ <View style={visible ? styles.showModal : styles.hideModal}>
238
233
  <Modal animationType="slide" transparent={true} visible={visible}>
239
234
  {renderModalChildren()}
240
235
  </Modal>
241
236
  </View>
237
+ </Portal>
242
238
  {renderChildren()}
243
239
  </>);
244
240
  });
@@ -0,0 +1,39 @@
1
+ import React, { useEffect } from 'react';
2
+ import Reanimated, { Extrapolation, interpolate, useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
3
+ import { wrapChildren, extendObject } from './utils';
4
+ import { createFaces } from './pickerFaces';
5
+ import { usePickerViewColumnAnimationContext } from './pickerVIewContext';
6
+ const _PickerViewColumnItem = ({ item, index, itemHeight, itemWidth = '100%', textStyleFromParent, textStyle, hasVarDec, varContext, textProps, visibleCount, onItemLayout }) => {
7
+ const offsetYShared = usePickerViewColumnAnimationContext();
8
+ const facesShared = useSharedValue(createFaces(itemHeight, visibleCount));
9
+ useEffect(() => {
10
+ facesShared.value = createFaces(itemHeight, visibleCount);
11
+ }, [itemHeight]);
12
+ const animatedStyles = useAnimatedStyle(() => {
13
+ const inputRange = facesShared.value.map((f) => itemHeight * (index + f.index));
14
+ return {
15
+ opacity: interpolate(offsetYShared.value, inputRange, facesShared.value.map((x) => x.opacity), Extrapolation.CLAMP),
16
+ transform: [
17
+ { rotateX: interpolate(offsetYShared.value, inputRange, facesShared.value.map((x) => x.deg), Extrapolation.CLAMP) + 'deg' },
18
+ { translateY: interpolate(offsetYShared.value, inputRange, facesShared.value.map((x) => x.offsetY), Extrapolation.EXTEND) },
19
+ { scale: interpolate(offsetYShared.value, inputRange, facesShared.value.map((x) => x.scale), Extrapolation.EXTEND) }
20
+ ]
21
+ };
22
+ });
23
+ const strKey = `picker-column-item-${index}`;
24
+ const restProps = index === 0 ? { onLayout: onItemLayout } : {};
25
+ const itemProps = extendObject({
26
+ style: extendObject({ height: itemHeight, width: '100%' }, textStyleFromParent, textStyle, item.props.style)
27
+ }, restProps);
28
+ const realItem = React.cloneElement(item, itemProps);
29
+ return (<Reanimated.View key={strKey} style={[{ height: itemHeight, width: itemWidth }, animatedStyles]}>
30
+ {wrapChildren({ children: realItem }, {
31
+ hasVarDec,
32
+ varContext,
33
+ textStyle,
34
+ textProps
35
+ })}
36
+ </Reanimated.View>);
37
+ };
38
+ _PickerViewColumnItem.displayName = 'MpxPickerViewColumnItem';
39
+ export default _PickerViewColumnItem;
@@ -1,40 +1,70 @@
1
- import { Animated, SafeAreaView } from 'react-native';
2
- import React, { forwardRef, useRef, useState, useMemo, useCallback, useEffect } from 'react';
3
- import { useTransformStyle, splitStyle, splitProps, wrapChildren, useLayout, usePrevious } from './utils';
1
+ import React, { forwardRef, useRef, useState, useMemo, useEffect, useCallback } from 'react';
2
+ import { SafeAreaView, StyleSheet } from 'react-native';
3
+ import Reanimated, { useAnimatedRef, useScrollViewOffset } from 'react-native-reanimated';
4
+ import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS, useDebounceCallback, useStableCallback } from './utils';
4
5
  import useNodesRef from './useNodesRef';
5
- import { createFaces } from './pickerFaces';
6
- import PickerOverlay from './pickerOverlay';
7
- // 默认的单个选项高度
8
- const DefaultPickerItemH = 36;
9
- // 默认一屏可见选项个数
6
+ import PickerOverlay from './pickerViewOverlay';
7
+ import PickerMask from './pickerViewMask';
8
+ import MpxPickerVIewColumnItem from './mpx-picker-view-column-item';
9
+ import { PickerViewColumnAnimationContext } from './pickerVIewContext';
10
10
  const visibleCount = 5;
11
11
  const _PickerViewColumn = forwardRef((props, ref) => {
12
- const { columnData, columnIndex, initialIndex, onSelectChange, onColumnItemRawHChange, getInnerLayout, style, wrapperStyle, pickerOverlayStyle, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
12
+ const { columnData, columnIndex, columnStyle, initialIndex, onSelectChange, style, wrapperStyle, pickerMaskStyle, pickerOverlayStyle, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
13
13
  const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext });
14
- const { textStyle } = splitStyle(normalStyle);
14
+ const { textStyle: textStyleFromParent = {} } = splitStyle(columnStyle);
15
+ const { textStyle = {} } = splitStyle(normalStyle);
15
16
  const { textProps } = splitProps(props);
16
- const scrollViewRef = useRef(null);
17
- useNodesRef(props, ref, scrollViewRef, {});
18
- const { height: pickerH, itemHeight = DefaultPickerItemH } = wrapperStyle;
19
- const [itemRawH, setItemRawH] = useState(0); // 单个选项真实渲染高度
17
+ const scrollViewRef = useAnimatedRef();
18
+ const offsetYShared = useScrollViewOffset(scrollViewRef);
19
+ useNodesRef(props, ref, scrollViewRef, {
20
+ style: normalStyle
21
+ });
22
+ const { height: pickerH, itemHeight } = wrapperStyle;
23
+ const [itemRawH, setItemRawH] = useState(itemHeight);
20
24
  const maxIndex = useMemo(() => columnData.length - 1, [columnData]);
25
+ const prevScrollingInfo = useRef({ index: initialIndex, y: 0 });
21
26
  const touching = useRef(false);
22
27
  const scrolling = useRef(false);
23
28
  const activeIndex = useRef(initialIndex);
24
29
  const prevIndex = usePrevious(initialIndex);
25
30
  const prevMaxIndex = usePrevious(maxIndex);
26
- const initialOffset = useMemo(() => ({
27
- x: 0,
28
- y: itemRawH * initialIndex
29
- }), [itemRawH]);
31
+ const { layoutProps } = useLayout({
32
+ props,
33
+ hasSelfPercent,
34
+ setWidth,
35
+ setHeight,
36
+ nodeRef: scrollViewRef
37
+ });
38
+ // console.log('[mpx-picker-view-column], render ---> columnIndex=', columnIndex, 'initialIndex=', initialIndex, 'columnData=', columnData.length, 'pickerH=', pickerH, 'itemRawH=', itemRawH, 'itemHeight=', itemHeight)
39
+ const paddingHeight = useMemo(() => Math.round((pickerH - itemHeight) / 2), [pickerH, itemHeight]);
30
40
  const snapToOffsets = useMemo(() => columnData.map((_, i) => i * itemRawH), [columnData, itemRawH]);
31
41
  const contentContainerStyle = useMemo(() => {
32
- return [
33
- {
34
- paddingVertical: Math.round(pickerH - itemRawH) / 2
35
- }
36
- ];
37
- }, [pickerH, itemRawH]);
42
+ return [{ paddingVertical: paddingHeight }];
43
+ }, [paddingHeight]);
44
+ const getIndex = useCallback((y) => {
45
+ const calc = Math.round(y / itemRawH);
46
+ return Math.max(0, Math.min(calc, maxIndex));
47
+ }, [itemRawH, maxIndex]);
48
+ const getYofIndex = useCallback((index) => {
49
+ return index * itemRawH;
50
+ }, [itemRawH]);
51
+ const stableResetScrollPosition = useStableCallback((y) => {
52
+ // console.log('[mpx-picker-view-column], reset --->', 'columnIndex=', columnIndex, 'y=', y, touching.current, scrolling.current, itemRawH, 'snapToOffsets=', snapToOffsets)
53
+ if (touching.current || scrolling.current) {
54
+ return;
55
+ }
56
+ // needReset.current = true
57
+ if (y % itemRawH !== 0) {
58
+ scrolling.current = true;
59
+ const targetIndex = getIndex(y);
60
+ const targetY = getYofIndex(targetIndex);
61
+ scrollViewRef.current?.scrollTo({ x: 0, y: targetY, animated: false });
62
+ }
63
+ else {
64
+ onMomentumScrollEnd({ nativeEvent: { contentOffset: { y } } });
65
+ }
66
+ });
67
+ const debounceResetScrollPosition = useDebounceCallback(stableResetScrollPosition, 10);
38
68
  useEffect(() => {
39
69
  if (!scrollViewRef.current ||
40
70
  !itemRawH ||
@@ -46,122 +76,106 @@ const _PickerViewColumn = forwardRef((props, ref) => {
46
76
  maxIndex !== prevMaxIndex) {
47
77
  return;
48
78
  }
79
+ setTimeout(() => {
80
+ scrollViewRef.current?.scrollTo({
81
+ x: 0,
82
+ y: getYofIndex(initialIndex),
83
+ animated: false
84
+ });
85
+ }, isAndroid ? 200 : 0);
49
86
  activeIndex.current = initialIndex;
50
- scrollViewRef.current.scrollTo({
51
- x: 0,
52
- y: itemRawH * initialIndex,
53
- animated: false
54
- });
55
87
  }, [itemRawH, initialIndex]);
56
- const onScrollViewLayout = () => {
57
- getInnerLayout && getInnerLayout(layoutRef);
58
- };
59
- const { layoutRef, layoutProps } = useLayout({
60
- props,
61
- hasSelfPercent,
62
- setWidth,
63
- setHeight,
64
- nodeRef: scrollViewRef,
65
- onLayout: onScrollViewLayout
66
- });
67
- const onContentSizeChange = (w, h) => {
68
- scrollViewRef.current?.scrollTo({
69
- x: 0,
70
- y: itemRawH * initialIndex,
71
- animated: false
72
- });
88
+ const onContentSizeChange = (_w, h) => {
89
+ const y = getYofIndex(initialIndex);
90
+ if (y <= h) {
91
+ setTimeout(() => {
92
+ scrollViewRef.current?.scrollTo({ x: 0, y, animated: false });
93
+ }, 0);
94
+ }
73
95
  };
74
96
  const onItemLayout = (e) => {
75
97
  const { height: rawH } = e.nativeEvent.layout;
76
- if (rawH && itemRawH !== rawH) {
77
- setItemRawH(rawH);
78
- onColumnItemRawHChange(rawH);
98
+ const roundedH = Math.round(rawH);
99
+ if (roundedH && roundedH !== itemRawH) {
100
+ setItemRawH(roundedH);
79
101
  }
80
102
  };
81
- const onTouchStart = () => {
103
+ const onScrollBeginDrag = () => {
104
+ isIOS && debounceResetScrollPosition.clear();
82
105
  touching.current = true;
106
+ prevScrollingInfo.current = {
107
+ index: activeIndex.current,
108
+ y: getYofIndex(activeIndex.current)
109
+ };
83
110
  };
84
- const onTouchEnd = () => {
85
- touching.current = false;
86
- };
87
- const onTouchCancel = () => {
111
+ const onScrollEndDrag = (e) => {
88
112
  touching.current = false;
113
+ const { y } = e.nativeEvent.contentOffset;
114
+ if (isIOS) {
115
+ if (y >= 0 && y <= snapToOffsets[maxIndex]) {
116
+ debounceResetScrollPosition(y);
117
+ }
118
+ }
89
119
  };
90
120
  const onMomentumScrollBegin = () => {
121
+ isIOS && debounceResetScrollPosition.clear();
91
122
  scrolling.current = true;
92
123
  };
93
124
  const onMomentumScrollEnd = (e) => {
94
125
  scrolling.current = false;
95
- if (!itemRawH) {
96
- return;
97
- }
98
126
  const { y: scrollY } = e.nativeEvent.contentOffset;
99
- let calcIndex = Math.round(scrollY / itemRawH);
100
- activeIndex.current = calcIndex;
101
- if (calcIndex !== initialIndex) {
102
- calcIndex = Math.max(0, Math.min(calcIndex, maxIndex)) || 0;
127
+ // console.log('[mpx-picker-view-column], onMomentumScrollEnd --->', 'columnIndex=', columnIndex, scrollY, itemRawH)
128
+ if (isIOS && scrollY % itemRawH !== 0) {
129
+ return debounceResetScrollPosition(scrollY);
130
+ }
131
+ const calcIndex = getIndex(scrollY);
132
+ if (calcIndex !== activeIndex.current) {
133
+ activeIndex.current = calcIndex;
103
134
  onSelectChange(calcIndex);
104
135
  }
105
136
  };
106
- const offsetY = useRef(new Animated.Value(0)).current;
107
- const onScroll = useMemo(() => Animated.event([{ nativeEvent: { contentOffset: { y: offsetY } } }], {
108
- useNativeDriver: true
109
- }), [offsetY]);
110
- const faces = useMemo(() => createFaces(itemRawH, visibleCount), [itemRawH]);
111
- const getTransform = useCallback((index) => {
112
- const inputRange = faces.map((f) => itemRawH * (index + f.index));
113
- return {
114
- opacity: offsetY.interpolate({
115
- inputRange: inputRange,
116
- outputRange: faces.map((x) => x.opacity),
117
- extrapolate: 'clamp'
118
- }),
119
- rotateX: offsetY.interpolate({
120
- inputRange: inputRange,
121
- outputRange: faces.map((x) => `${x.deg}deg`),
122
- extrapolate: 'extend'
123
- }),
124
- translateY: offsetY.interpolate({
125
- inputRange: inputRange,
126
- outputRange: faces.map((x) => x.offsetY),
127
- extrapolate: 'extend'
128
- })
129
- };
130
- }, [offsetY, faces, itemRawH]);
131
- const renderInnerchild = () => columnData.map((item, index) => {
132
- const InnerProps = index === 0 ? { onLayout: onItemLayout } : {};
133
- const strKey = `picker-column-${columnIndex}-${index}`;
134
- const { opacity, rotateX, translateY } = getTransform(index);
135
- return (<Animated.View key={strKey} {...InnerProps} style={[
136
- {
137
- height: itemHeight || DefaultPickerItemH,
138
- width: '100%',
139
- opacity,
140
- transform: [
141
- { translateY },
142
- { rotateX },
143
- { perspective: 1000 } // 适配 Android
144
- ]
137
+ const onScroll = (e) => {
138
+ // 全局注册的振动触感 hook
139
+ const pickerVibrate = global.__mpx?.config?.rnConfig?.pickerVibrate;
140
+ if (typeof pickerVibrate !== 'function') {
141
+ return;
142
+ }
143
+ const { y } = e.nativeEvent.contentOffset;
144
+ const { index: prevIndex, y: _y } = prevScrollingInfo.current;
145
+ if (touching.current || scrolling.current) {
146
+ if (Math.abs(y - _y) >= itemRawH) {
147
+ const currentId = getIndex(y);
148
+ if (currentId !== prevIndex) {
149
+ prevScrollingInfo.current = {
150
+ index: currentId,
151
+ y: getYofIndex(currentId)
152
+ };
153
+ // vibrateShort({ type: 'selection' })
154
+ pickerVibrate();
145
155
  }
146
- ]}>
147
- {wrapChildren({ children: item }, {
148
- hasVarDec,
149
- varContext: varContextRef.current,
150
- textStyle,
151
- textProps
152
- })}
153
- </Animated.View>);
156
+ }
157
+ }
158
+ };
159
+ const renderInnerchild = () => columnData.map((item, index) => {
160
+ return (<MpxPickerVIewColumnItem key={index} item={item} index={index} itemHeight={itemHeight} textStyleFromParent={textStyleFromParent} textStyle={textStyle} hasVarDec={hasVarDec} varContext={varContextRef.current} textProps={textProps} visibleCount={visibleCount} onItemLayout={onItemLayout}/>);
154
161
  });
155
162
  const renderScollView = () => {
156
- return (<Animated.ScrollView ref={scrollViewRef} bounces={true} horizontal={false} pagingEnabled={false} nestedScrollEnabled={true} removeClippedSubviews={true} showsVerticalScrollIndicator={false} showsHorizontalScrollIndicator={false} {...layoutProps} scrollEventThrottle={16} contentContainerStyle={contentContainerStyle} contentOffset={initialOffset} snapToOffsets={snapToOffsets} onContentSizeChange={onContentSizeChange} onScroll={onScroll} onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} onTouchCancel={onTouchCancel} onMomentumScrollBegin={onMomentumScrollBegin} onMomentumScrollEnd={onMomentumScrollEnd}>
157
- {renderInnerchild()}
158
- </Animated.ScrollView>);
163
+ return (<PickerViewColumnAnimationContext.Provider value={offsetYShared}>
164
+ <Reanimated.ScrollView ref={scrollViewRef} bounces={true} horizontal={false} nestedScrollEnabled={true} removeClippedSubviews={false} showsVerticalScrollIndicator={false} showsHorizontalScrollIndicator={false} scrollEventThrottle={16} {...layoutProps} style={[{ width: '100%' }]} decelerationRate="fast" snapToOffsets={snapToOffsets} onScroll={onScroll} onScrollBeginDrag={onScrollBeginDrag} onScrollEndDrag={onScrollEndDrag} onMomentumScrollBegin={onMomentumScrollBegin} onMomentumScrollEnd={onMomentumScrollEnd} onContentSizeChange={onContentSizeChange} contentContainerStyle={contentContainerStyle}>
165
+ {renderInnerchild()}
166
+ </Reanimated.ScrollView>
167
+ </PickerViewColumnAnimationContext.Provider>);
159
168
  };
160
169
  const renderOverlay = () => (<PickerOverlay itemHeight={itemHeight} overlayItemStyle={pickerOverlayStyle}/>);
161
- return (<SafeAreaView style={[{ display: 'flex', flex: 1 }]}>
170
+ const renderMask = () => (<PickerMask itemHeight={itemHeight} maskContainerStyle={pickerMaskStyle}/>);
171
+ return (<SafeAreaView style={[styles.wrapper, normalStyle]}>
162
172
  {renderScollView()}
173
+ {renderMask()}
163
174
  {renderOverlay()}
164
175
  </SafeAreaView>);
165
176
  });
177
+ const styles = StyleSheet.create({
178
+ wrapper: { display: 'flex', flex: 1 }
179
+ });
166
180
  _PickerViewColumn.displayName = 'MpxPickerViewColumn';
167
181
  export default _PickerViewColumn;
@@ -1,8 +1,8 @@
1
1
  import { View } from 'react-native';
2
- import React, { forwardRef, useState, useRef } from 'react';
2
+ import React, { forwardRef, useRef } from 'react';
3
3
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
4
4
  import useNodesRef from './useNodesRef';
5
- import { useLayout, splitProps, splitStyle, wrapChildren, parseInlineStyle, useTransformStyle, useDebounceCallback, useStableCallback, extendObject } from './utils';
5
+ import { useLayout, splitProps, splitStyle, wrapChildren, parseInlineStyle, useTransformStyle, extendObject } from './utils';
6
6
  const styles = {
7
7
  wrapper: {
8
8
  display: 'flex',
@@ -13,66 +13,69 @@ const styles = {
13
13
  alignItems: 'center'
14
14
  }
15
15
  };
16
+ const DefaultPickerItemH = 36;
16
17
  const _PickerView = forwardRef((props, ref) => {
17
18
  const { children, value = [], bindchange, style, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
18
- // indicatorStyle 需要转换为rn的style
19
- // 微信设置到pick-view上上设置的normalStyle如border等需要转换成RN的style然后进行透传
20
19
  const indicatorStyle = parseInlineStyle(props['indicator-style']);
20
+ const pickerMaskStyle = parseInlineStyle(props['mask-style']);
21
21
  const { height: indicatorH, ...pickerOverlayStyle } = indicatorStyle;
22
- const [pickMaxH, setPickMaxH] = useState(0);
23
22
  const nodeRef = useRef(null);
24
23
  const cloneRef = useRef(null);
25
24
  const activeValueRef = useRef(value);
26
25
  activeValueRef.current = value.slice();
26
+ const snapActiveValueRef = useRef(null);
27
+ console.log('[mpx-picker-view] value=', value, Date.now());
27
28
  const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext });
28
- useNodesRef(props, ref, nodeRef, {});
29
- const {
30
- // 存储layout布局信息
31
- layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: nodeRef });
29
+ useNodesRef(props, ref, nodeRef, {
30
+ style: normalStyle
31
+ });
32
+ const { layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: nodeRef });
32
33
  const { textProps } = splitProps(props);
33
34
  const { textStyle } = splitStyle(normalStyle);
34
- const onColumnItemRawHChange = (height) => {
35
- if (height > pickMaxH) {
36
- setPickMaxH(height);
37
- }
38
- };
39
- const bindchangeDebounce = useDebounceCallback(useStableCallback(bindchange), 300);
40
35
  const onSelectChange = (columnIndex, selectedIndex) => {
41
- bindchangeDebounce.clear();
42
36
  const activeValue = activeValueRef.current;
43
37
  activeValue[columnIndex] = selectedIndex;
38
+ console.log('[mpx-picker-view], onSelectChange ---> columnIndex=', columnIndex, 'selectedIndex=', selectedIndex, 'activeValue=', activeValue);
44
39
  const eventData = getCustomEvent('change', {}, { detail: { value: activeValue, source: 'change' }, layoutRef });
45
- bindchangeDebounce(eventData);
40
+ bindchange?.(eventData);
41
+ snapActiveValueRef.current = activeValueRef.current;
46
42
  };
47
- const onInitialChange = (value) => {
48
- const eventData = getCustomEvent('change', {}, { detail: { value, source: 'change' }, layoutRef });
49
- bindchange?.(eventData); // immediate
43
+ const hasDiff = (a = [], b) => {
44
+ return a.some((v, i) => v !== b[i]);
45
+ };
46
+ const onInitialChange = (isInvalid, value) => {
47
+ if (isInvalid || !snapActiveValueRef.current || hasDiff(snapActiveValueRef.current, value)) {
48
+ console.log('[mpx-picker-view], onInitialChange ===> value=', value);
49
+ const eventData = getCustomEvent('change', {}, { detail: { value, source: 'change' }, layoutRef });
50
+ bindchange?.(eventData);
51
+ snapActiveValueRef.current = value.slice();
52
+ }
50
53
  };
51
54
  const innerProps = useInnerProps(props, extendObject({
52
55
  ref: nodeRef,
53
- style: extendObject(normalStyle, layoutStyle, {
56
+ style: extendObject({}, normalStyle, layoutStyle, {
54
57
  position: 'relative',
55
58
  overflow: 'hidden'
56
59
  }),
57
60
  layoutProps
58
61
  }), ['enable-offset'], { layoutRef });
59
62
  const renderColumn = (child, index, columnData, initialIndex) => {
60
- const extraProps = {};
61
63
  const childProps = child?.props || {};
62
- const wrappedProps = extendObject(childProps, {
64
+ const wrappedProps = extendObject({}, childProps, {
63
65
  columnData,
64
66
  ref: cloneRef,
65
67
  columnIndex: index,
66
68
  key: `pick-view-${index}`,
67
69
  wrapperStyle: {
68
- height: normalStyle?.height || 0,
69
- itemHeight: indicatorH || 0
70
+ height: normalStyle?.height || DefaultPickerItemH,
71
+ itemHeight: indicatorH || DefaultPickerItemH
70
72
  },
71
- onColumnItemRawHChange,
73
+ columnStyle: normalStyle,
72
74
  onSelectChange: onSelectChange.bind(null, index),
73
75
  initialIndex,
74
- pickerOverlayStyle
75
- }, extraProps);
76
+ pickerOverlayStyle,
77
+ pickerMaskStyle
78
+ });
76
79
  const realElement = React.cloneElement(child, wrappedProps);
77
80
  return wrapChildren({
78
81
  children: realElement
@@ -108,7 +111,7 @@ const _PickerView = forwardRef((props, ref) => {
108
111
  validValue.push(validIndex);
109
112
  renderColumns.push(renderColumn(item, index, columnData, validIndex));
110
113
  });
111
- isInvalid && onInitialChange(validValue);
114
+ onInitialChange(isInvalid, validValue);
112
115
  return renderColumns;
113
116
  };
114
117
  return (<View {...innerProps}>