@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.
- package/README.md +1 -1
- package/lib/config.js +14 -0
- package/lib/dependencies/AddEntryDependency.js +24 -0
- package/lib/dependencies/ResolveDependency.js +5 -0
- package/lib/index.js +38 -7
- package/lib/json-compiler/helper.js +3 -3
- package/lib/loader.js +52 -0
- package/lib/platform/template/wx/component-config/button.js +14 -2
- package/lib/platform/template/wx/component-config/image.js +4 -0
- package/lib/platform/template/wx/component-config/input.js +5 -1
- package/lib/platform/template/wx/component-config/rich-text.js +4 -0
- package/lib/platform/template/wx/component-config/scroll-view.js +4 -0
- package/lib/platform/template/wx/component-config/swiper.js +1 -1
- package/lib/platform/template/wx/component-config/switch.js +4 -0
- package/lib/platform/template/wx/component-config/text.js +4 -0
- package/lib/platform/template/wx/component-config/textarea.js +6 -1
- package/lib/platform/template/wx/component-config/view.js +4 -0
- package/lib/platform/template/wx/index.js +127 -1
- package/lib/react/processTemplate.js +3 -0
- package/lib/resolve-loader.js +4 -1
- package/lib/runtime/components/react/context.ts +4 -0
- package/lib/runtime/components/react/dist/context.js +5 -0
- package/lib/runtime/components/react/dist/event.config.js +24 -24
- package/lib/runtime/components/react/dist/getInnerListeners.js +183 -166
- package/lib/runtime/components/react/dist/locale-provider.jsx +15 -0
- package/lib/runtime/components/react/dist/mpx-button.jsx +39 -74
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +30 -12
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +13 -19
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +29 -38
- package/lib/runtime/components/react/dist/mpx-form.jsx +16 -19
- package/lib/runtime/components/react/dist/mpx-icon.jsx +8 -16
- package/lib/runtime/components/react/dist/mpx-image.jsx +295 -0
- package/lib/runtime/components/react/dist/mpx-input.jsx +54 -27
- package/lib/runtime/components/react/dist/mpx-label.jsx +15 -22
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +13 -16
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +14 -14
- package/lib/runtime/components/react/dist/mpx-navigator.jsx +2 -4
- package/lib/runtime/components/react/dist/mpx-picker/date.jsx +6 -2
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +5 -3
- package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +6 -2
- package/lib/runtime/components/react/dist/mpx-picker/region.jsx +6 -2
- package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +6 -2
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +10 -14
- package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +39 -0
- package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +126 -112
- package/lib/runtime/components/react/dist/mpx-picker-view.jsx +32 -29
- package/lib/runtime/components/react/dist/mpx-portal/portal-consumer.jsx +23 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +124 -0
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +40 -0
- package/lib/runtime/components/react/dist/mpx-portal.jsx +12 -0
- package/lib/runtime/components/react/dist/mpx-provider.jsx +31 -0
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +11 -19
- package/lib/runtime/components/react/dist/mpx-radio.jsx +27 -42
- package/lib/runtime/components/react/dist/mpx-rich-text/html.js +39 -0
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +62 -0
- package/lib/runtime/components/react/dist/mpx-root-portal.jsx +7 -5
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +62 -47
- package/lib/runtime/components/react/dist/mpx-simple-text.jsx +11 -0
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +28 -9
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +613 -0
- package/lib/runtime/components/react/dist/mpx-switch.jsx +20 -10
- package/lib/runtime/components/react/dist/mpx-text.jsx +11 -10
- package/lib/runtime/components/react/dist/mpx-textarea.jsx +8 -3
- package/lib/runtime/components/react/dist/mpx-view.jsx +37 -89
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +205 -46
- package/lib/runtime/components/react/dist/pickerFaces.js +12 -6
- package/lib/runtime/components/react/dist/pickerVIewContext.js +9 -0
- package/lib/runtime/components/react/dist/pickerViewMask.jsx +18 -0
- package/lib/runtime/components/react/dist/{pickerOverlay.jsx → pickerViewOverlay.jsx} +5 -3
- package/lib/runtime/components/react/dist/useAnimationHooks.js +50 -12
- package/lib/runtime/components/react/dist/utils.jsx +83 -28
- package/lib/runtime/components/react/getInnerListeners.ts +35 -28
- package/lib/runtime/components/react/mpx-button.tsx +55 -36
- package/lib/runtime/components/react/mpx-canvas/index.tsx +2 -2
- package/lib/runtime/components/react/mpx-checkbox-group.tsx +13 -12
- package/lib/runtime/components/react/mpx-checkbox.tsx +28 -28
- package/lib/runtime/components/react/mpx-form.tsx +10 -8
- package/lib/runtime/components/react/mpx-icon.tsx +10 -15
- package/lib/runtime/components/react/mpx-image.tsx +396 -0
- package/lib/runtime/components/react/mpx-input.tsx +61 -33
- package/lib/runtime/components/react/mpx-label.tsx +14 -13
- package/lib/runtime/components/react/mpx-movable-area.tsx +8 -7
- package/lib/runtime/components/react/mpx-movable-view.tsx +1 -1
- package/lib/runtime/components/react/mpx-picker/date.tsx +5 -2
- package/lib/runtime/components/react/mpx-picker/index.tsx +3 -2
- package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +5 -2
- package/lib/runtime/components/react/mpx-picker/region.tsx +5 -2
- package/lib/runtime/components/react/mpx-picker/selector.tsx +5 -2
- package/lib/runtime/components/react/mpx-picker/time.tsx +10 -15
- package/lib/runtime/components/react/mpx-picker/type.ts +48 -43
- package/lib/runtime/components/react/mpx-picker-view-column.tsx +4 -1
- package/lib/runtime/components/react/mpx-picker-view.tsx +7 -1
- package/lib/runtime/components/react/mpx-radio-group.tsx +11 -12
- package/lib/runtime/components/react/mpx-radio.tsx +26 -29
- package/lib/runtime/components/react/mpx-scroll-view.tsx +32 -30
- package/lib/runtime/components/react/mpx-simple-text.tsx +18 -0
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +4 -2
- package/lib/runtime/components/react/mpx-swiper-item.tsx +3 -2
- package/lib/runtime/components/react/mpx-switch.tsx +10 -8
- package/lib/runtime/components/react/mpx-text.tsx +6 -2
- package/lib/runtime/components/react/mpx-view.tsx +37 -45
- package/lib/runtime/components/react/mpx-web-view.tsx +25 -15
- package/lib/runtime/components/react/types/global.d.ts +1 -16
- package/lib/runtime/components/react/utils.tsx +24 -24
- package/lib/runtime/components/tenon/getInnerListeners.js +334 -0
- package/lib/runtime/components/tenon/tenon-button.vue +309 -0
- package/lib/runtime/components/tenon/tenon-image.vue +66 -0
- package/lib/runtime/components/tenon/tenon-input.vue +171 -0
- package/lib/runtime/components/tenon/tenon-rich-text.vue +26 -0
- package/lib/runtime/components/tenon/tenon-scroll-view.vue +127 -0
- package/lib/runtime/components/tenon/tenon-switch.vue +96 -0
- package/lib/runtime/components/tenon/tenon-text.vue +70 -0
- package/lib/runtime/components/tenon/tenon-textarea.vue +86 -0
- package/lib/runtime/components/tenon/tenon-view.vue +93 -0
- package/lib/runtime/components/web/getInnerListeners.js +6 -6
- package/lib/runtime/components/web/mpx-movable-view.vue +334 -344
- package/lib/runtime/components/web/mpx-picker-view-column.vue +75 -75
- package/lib/runtime/components/web/mpx-picker.vue +382 -385
- package/lib/runtime/components/web/mpx-web-view.vue +162 -162
- package/lib/runtime/optionProcessor.js +7 -16
- package/lib/runtime/optionProcessor.tenon.js +84 -0
- package/lib/runtime/utils.js +2 -0
- package/lib/style-compiler/index.js +1 -1
- package/lib/style-compiler/plugins/hm.js +20 -0
- package/lib/template-compiler/bind-this.js +7 -2
- package/lib/template-compiler/compiler.js +67 -40
- package/lib/template-compiler/gen-node-react.js +2 -2
- package/lib/tenon/index.js +112 -0
- package/lib/tenon/processJSON.js +352 -0
- package/lib/tenon/processScript.js +198 -0
- package/lib/tenon/processStyles.js +21 -0
- package/lib/tenon/processTemplate.js +125 -0
- package/lib/tenon/script-helper.js +223 -0
- package/lib/utils/env.js +6 -1
- package/lib/utils/get-relative-path.js +25 -0
- package/package.json +7 -3
- package/LICENSE +0 -433
- package/lib/runtime/components/react/dist/mpx-image/index.jsx +0 -226
- package/lib/runtime/components/react/dist/mpx-image/svg.jsx +0 -7
- package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +0 -478
- package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +0 -68
- package/lib/runtime/components/react/dist/mpx-swiper/type.js +0 -1
- package/lib/runtime/components/react/mpx-image/index.tsx +0 -345
- 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
|
-
...
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
15
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
<
|
|
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 {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
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
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
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,
|
|
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(
|
|
14
|
+
const { textStyle: textStyleFromParent = {} } = splitStyle(columnStyle);
|
|
15
|
+
const { textStyle = {} } = splitStyle(normalStyle);
|
|
15
16
|
const { textProps } = splitProps(props);
|
|
16
|
-
const scrollViewRef =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}, [
|
|
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
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
98
|
+
const roundedH = Math.round(rawH);
|
|
99
|
+
if (roundedH && roundedH !== itemRawH) {
|
|
100
|
+
setItemRawH(roundedH);
|
|
79
101
|
}
|
|
80
102
|
};
|
|
81
|
-
const
|
|
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
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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 (<
|
|
157
|
-
{
|
|
158
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
30
|
-
|
|
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
|
-
|
|
40
|
+
bindchange?.(eventData);
|
|
41
|
+
snapActiveValueRef.current = activeValueRef.current;
|
|
46
42
|
};
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
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 ||
|
|
69
|
-
itemHeight: indicatorH ||
|
|
70
|
+
height: normalStyle?.height || DefaultPickerItemH,
|
|
71
|
+
itemHeight: indicatorH || DefaultPickerItemH
|
|
70
72
|
},
|
|
71
|
-
|
|
73
|
+
columnStyle: normalStyle,
|
|
72
74
|
onSelectChange: onSelectChange.bind(null, index),
|
|
73
75
|
initialIndex,
|
|
74
|
-
pickerOverlayStyle
|
|
75
|
-
|
|
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
|
|
114
|
+
onInitialChange(isInvalid, validValue);
|
|
112
115
|
return renderColumns;
|
|
113
116
|
};
|
|
114
117
|
return (<View {...innerProps}>
|