@mpxjs/webpack-plugin 2.10.3 → 2.10.4
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/lib/config.js +2 -1
- package/lib/index.js +1 -1
- package/lib/platform/json/wx/index.js +6 -3
- package/lib/platform/style/wx/index.js +23 -12
- package/lib/platform/template/wx/component-config/button.js +19 -2
- package/lib/platform/template/wx/component-config/canvas.js +4 -0
- package/lib/platform/template/wx/component-config/checkbox-group.js +4 -0
- package/lib/platform/template/wx/component-config/checkbox.js +4 -0
- package/lib/platform/template/wx/component-config/cover-image.js +7 -1
- package/lib/platform/template/wx/component-config/cover-view.js +4 -0
- package/lib/platform/template/wx/component-config/fix-component-name.js +3 -2
- package/lib/platform/template/wx/component-config/form.js +7 -1
- package/lib/platform/template/wx/component-config/icon.js +4 -0
- package/lib/platform/template/wx/component-config/image.js +7 -1
- package/lib/platform/template/wx/component-config/input.js +18 -3
- package/lib/platform/template/wx/component-config/label.js +4 -0
- package/lib/platform/template/wx/component-config/movable-area.js +7 -1
- package/lib/platform/template/wx/component-config/movable-view.js +12 -3
- package/lib/platform/template/wx/component-config/navigator.js +4 -0
- package/lib/platform/template/wx/component-config/picker-view-column.js +4 -0
- package/lib/platform/template/wx/component-config/picker-view.js +7 -1
- package/lib/platform/template/wx/component-config/picker.js +7 -1
- package/lib/platform/template/wx/component-config/radio-group.js +4 -0
- package/lib/platform/template/wx/component-config/radio.js +4 -0
- package/lib/platform/template/wx/component-config/rich-text.js +4 -0
- package/lib/platform/template/wx/component-config/root-portal.js +4 -0
- package/lib/platform/template/wx/component-config/scroll-view.js +10 -2
- package/lib/platform/template/wx/component-config/swiper-item.js +7 -1
- package/lib/platform/template/wx/component-config/swiper.js +12 -3
- package/lib/platform/template/wx/component-config/switch.js +4 -0
- package/lib/platform/template/wx/component-config/text.js +24 -3
- package/lib/platform/template/wx/component-config/textarea.js +17 -2
- package/lib/platform/template/wx/component-config/unsupported.js +7 -0
- package/lib/platform/template/wx/component-config/video.js +10 -2
- package/lib/platform/template/wx/component-config/view.js +11 -1
- package/lib/platform/template/wx/component-config/web-view.js +4 -0
- package/lib/platform/template/wx/index.js +42 -75
- package/lib/react/processScript.js +1 -18
- package/lib/runtime/components/react/dist/event.config.js +1 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +18 -7
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-inline-text.jsx +11 -0
- package/lib/runtime/components/react/dist/mpx-input.jsx +3 -6
- package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-picker/date.jsx +194 -68
- package/lib/runtime/components/react/dist/mpx-picker/dateData.js +17 -0
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +178 -96
- package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +79 -139
- package/lib/runtime/components/react/dist/mpx-picker/region.jsx +190 -90
- package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +60 -75
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +100 -228
- package/lib/runtime/components/react/dist/{mpx-picker-view.jsx → mpx-picker-view/index.jsx} +3 -3
- package/lib/runtime/components/react/dist/{mpx-picker-view-column.jsx → mpx-picker-view-column/index.jsx} +64 -16
- package/lib/runtime/components/react/dist/{mpx-picker-view-column-item.jsx → mpx-picker-view-column/pickerViewColumnItem.jsx} +8 -5
- package/lib/runtime/components/react/dist/{pickerFaces.js → mpx-picker-view-column/pickerViewFaces.js} +6 -0
- package/lib/runtime/components/react/dist/mpx-popup/index.jsx +61 -0
- package/lib/runtime/components/react/dist/mpx-popup/popupBase.jsx +92 -0
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +192 -25
- package/lib/runtime/components/react/dist/mpx-simple-text.jsx +8 -7
- package/lib/runtime/components/react/dist/mpx-simple-view.jsx +11 -15
- package/lib/runtime/components/react/dist/mpx-video.jsx +3 -3
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +7 -4
- package/lib/runtime/components/react/dist/utils.jsx +2 -1
- package/lib/runtime/components/react/event.config.ts +2 -0
- package/lib/runtime/components/react/getInnerListeners.ts +28 -25
- package/lib/runtime/components/react/mpx-canvas/index.tsx +2 -2
- package/lib/runtime/components/react/mpx-inline-text.tsx +18 -0
- package/lib/runtime/components/react/mpx-input.tsx +2 -6
- package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +1 -1
- package/lib/runtime/components/react/mpx-picker/date.tsx +226 -69
- package/lib/runtime/components/react/mpx-picker/dateData.ts +22 -0
- package/lib/runtime/components/react/mpx-picker/index.tsx +239 -118
- package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +96 -139
- package/lib/runtime/components/react/mpx-picker/region.tsx +217 -89
- package/lib/runtime/components/react/mpx-picker/selector.tsx +75 -80
- package/lib/runtime/components/react/mpx-picker/time.tsx +119 -236
- package/lib/runtime/components/react/mpx-picker/type.ts +85 -71
- package/lib/runtime/components/react/{mpx-picker-view.tsx → mpx-picker-view/index.tsx} +7 -7
- package/lib/runtime/components/react/{mpx-picker-view-column.tsx → mpx-picker-view-column/index.tsx} +70 -19
- package/lib/runtime/components/react/{mpx-picker-view-column-item.tsx → mpx-picker-view-column/pickerViewColumnItem.tsx} +8 -5
- package/lib/runtime/components/react/{pickerFaces.ts → mpx-picker-view-column/pickerViewFaces.ts} +7 -0
- package/lib/runtime/components/react/mpx-popup/index.tsx +86 -0
- package/lib/runtime/components/react/mpx-popup/popupBase.tsx +130 -0
- package/lib/runtime/components/react/mpx-scroll-view.tsx +249 -43
- package/lib/runtime/components/react/mpx-simple-text.tsx +10 -8
- package/lib/runtime/components/react/mpx-simple-view.tsx +11 -16
- package/lib/runtime/components/react/mpx-video.tsx +2 -2
- package/lib/runtime/components/react/mpx-web-view.tsx +7 -4
- package/lib/runtime/components/react/types/getInnerListeners.d.ts +5 -1
- package/lib/runtime/components/react/types/global.d.ts +1 -1
- package/lib/runtime/components/react/utils.tsx +3 -2
- package/lib/runtime/components/web/mini-video-controls.min.js +1 -1
- package/lib/runtime/components/web/mpx-input.vue +1 -1
- package/lib/runtime/stringify.wxs +2 -2
- package/lib/template-compiler/compiler.js +8 -8
- package/lib/utils/env.js +1 -1
- package/package.json +4 -5
- /package/lib/runtime/components/react/dist/{pickerVIewContext.js → mpx-picker-view/pickerVIewContext.js} +0 -0
- /package/lib/runtime/components/react/dist/{pickerViewIndicator.jsx → mpx-picker-view-column/pickerViewIndicator.jsx} +0 -0
- /package/lib/runtime/components/react/dist/{pickerViewMask.jsx → mpx-picker-view-column/pickerViewMask.jsx} +0 -0
- /package/lib/runtime/components/react/{pickerVIewContext.ts → mpx-picker-view/pickerVIewContext.ts} +0 -0
- /package/lib/runtime/components/react/{pickerViewIndicator.tsx → mpx-picker-view-column/pickerViewIndicator.tsx} +0 -0
- /package/lib/runtime/components/react/{pickerViewMask.tsx → mpx-picker-view-column/pickerViewMask.tsx} +0 -0
|
@@ -1,242 +1,114 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
width: '100%',
|
|
16
|
-
height: '100%'
|
|
1
|
+
import React, { forwardRef, useRef, useState, useEffect, useImperativeHandle } from 'react';
|
|
2
|
+
import { StyleSheet, Text } from 'react-native';
|
|
3
|
+
import { warn } from '@mpxjs/utils';
|
|
4
|
+
import MpxPickerView from '../mpx-picker-view';
|
|
5
|
+
import MpxPickerViewColumn from '../mpx-picker-view-column';
|
|
6
|
+
import { useUpdateEffect } from '../utils';
|
|
7
|
+
const styles = StyleSheet.create({
|
|
8
|
+
pickerContainer: {
|
|
9
|
+
width: 120,
|
|
10
|
+
height: 240,
|
|
11
|
+
alignSelf: 'center',
|
|
12
|
+
paddingHorizontal: 10,
|
|
13
|
+
borderTopLeftRadius: 10,
|
|
14
|
+
borderTopRightRadius: 10
|
|
17
15
|
},
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
height: 0
|
|
16
|
+
pickerIndicator: {
|
|
17
|
+
height: 45
|
|
21
18
|
},
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
centeredView: {
|
|
27
|
-
position: 'absolute',
|
|
28
|
-
bottom: 0,
|
|
29
|
-
width: '100%',
|
|
30
|
-
overflow: 'scroll'
|
|
31
|
-
},
|
|
32
|
-
btnLine: {
|
|
33
|
-
width: '100%',
|
|
34
|
-
flex: 1,
|
|
35
|
-
flexDirection: 'row',
|
|
36
|
-
justifyContent: 'space-between',
|
|
37
|
-
borderColor: 20,
|
|
38
|
-
borderBottomWidth: 1,
|
|
39
|
-
backgroundColor: 'white',
|
|
40
|
-
paddingLeft: 40,
|
|
41
|
-
paddingRight: 40
|
|
42
|
-
},
|
|
43
|
-
cancel: {
|
|
44
|
-
height: 50,
|
|
45
|
-
display: 'flex',
|
|
46
|
-
justifyContent: 'center'
|
|
47
|
-
},
|
|
48
|
-
ok: {
|
|
49
|
-
height: 50,
|
|
50
|
-
display: 'flex',
|
|
51
|
-
justifyContent: 'center'
|
|
52
|
-
},
|
|
53
|
-
btntext: {
|
|
54
|
-
color: '#0ae',
|
|
55
|
-
fontSize: 18
|
|
19
|
+
pickerItem: {
|
|
20
|
+
fontSize: 20,
|
|
21
|
+
lineHeight: 45,
|
|
22
|
+
textAlign: 'center'
|
|
56
23
|
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// [9, 59] to 09:59
|
|
63
|
-
function formatStr(arr) {
|
|
64
|
-
let [hour, minute] = arr;
|
|
65
|
-
if (hour < 10) {
|
|
66
|
-
hour = '0' + hour;
|
|
24
|
+
});
|
|
25
|
+
const time2Array = (time, defaultValue = [0, 0]) => {
|
|
26
|
+
if (typeof time !== 'string') {
|
|
27
|
+
warn('[mpx runtime warn]: mpx-picker prop time must be a string');
|
|
28
|
+
return defaultValue;
|
|
67
29
|
}
|
|
68
|
-
|
|
69
|
-
|
|
30
|
+
let [hour = 0, minute = 0] = time.split(':').map(Number);
|
|
31
|
+
hour = Math.min(Math.max(hour, 0), 23);
|
|
32
|
+
minute = Math.min(Math.max(minute, 0), 59);
|
|
33
|
+
return [hour, minute];
|
|
34
|
+
};
|
|
35
|
+
const time2String = (time) => {
|
|
36
|
+
return time.map(i => i.toString().padStart(2, '0')).join(':');
|
|
37
|
+
};
|
|
38
|
+
const time2Minutes = (time) => {
|
|
39
|
+
return time[0] * 60 + time[1];
|
|
40
|
+
};
|
|
41
|
+
const calibrateTime = (time, start = [0, 0], end = [23, 59]) => {
|
|
42
|
+
time = typeof time === 'string' ? time2Array(time) : time;
|
|
43
|
+
start = typeof start === 'string' ? time2Array(start) : start;
|
|
44
|
+
end = typeof end === 'string' ? time2Array(end) : end;
|
|
45
|
+
const current = time2Minutes(time);
|
|
46
|
+
if (current < time2Minutes(start)) {
|
|
47
|
+
return start;
|
|
70
48
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
function generateMinute() {
|
|
74
|
-
const arrMinute = [];
|
|
75
|
-
for (let i = 0; i <= 59; i++) {
|
|
76
|
-
const obj = {
|
|
77
|
-
label: toSingleStr(i),
|
|
78
|
-
value: i,
|
|
79
|
-
children: []
|
|
80
|
-
};
|
|
81
|
-
arrMinute.push(obj);
|
|
49
|
+
else if (current > time2Minutes(end)) {
|
|
50
|
+
return end;
|
|
82
51
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
function generateColumns() {
|
|
86
|
-
const pickData = [];
|
|
87
|
-
for (let i = 0; i <= 23; i++) {
|
|
88
|
-
const obj = {
|
|
89
|
-
label: toSingleStr(i),
|
|
90
|
-
value: i,
|
|
91
|
-
children: generateMinute()
|
|
92
|
-
};
|
|
93
|
-
pickData.push(obj);
|
|
52
|
+
else {
|
|
53
|
+
return time;
|
|
94
54
|
}
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
function toStr(time) {
|
|
101
|
-
const [hour, minute] = formatStrToInt(time);
|
|
102
|
-
const newHour = toSingleStr(hour);
|
|
103
|
-
const newMinute = toSingleStr(minute);
|
|
104
|
-
return '' + newHour + newMinute;
|
|
105
|
-
}
|
|
106
|
-
function checkSelectedIsValid(strStart, strEnd, selected) {
|
|
107
|
-
const strSel = '' + toSingleStr(selected[0]) + toSingleStr(selected[1]);
|
|
108
|
-
if (strSel < strStart || strSel > strEnd)
|
|
109
|
-
return false;
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* [{label:'', value: '', key: '', children: []}]
|
|
114
|
-
label: string | ReactNode
|
|
115
|
-
value: string | number
|
|
116
|
-
key?: string | number
|
|
117
|
-
children?: PickerColumnItem[]
|
|
118
|
-
*/
|
|
119
|
-
// start="02:10" end = 23:01
|
|
120
|
-
const _TimePicker = forwardRef((props, ref) => {
|
|
121
|
-
const { children, start, end, value, bindchange, bindcancel, style } = props;
|
|
122
|
-
const defaultProps = {
|
|
123
|
-
start: '00:10',
|
|
124
|
-
end: '23:59'
|
|
125
|
-
};
|
|
126
|
-
const defaultValue = formatStrToInt(value);
|
|
127
|
-
const [timevalue, setTimeValue] = useState(defaultValue);
|
|
128
|
-
// 存储layout布局信息
|
|
129
|
-
const layoutRef = useRef({});
|
|
130
|
-
const viewRef = useRef(null);
|
|
55
|
+
};
|
|
56
|
+
const hoursRange = Array.from({ length: 24 }, (_, i) => i.toString().padStart(2, '0'));
|
|
57
|
+
const minutesRange = Array.from({ length: 60 }, (_, i) => i.toString().padStart(2, '0'));
|
|
58
|
+
const PickerTime = forwardRef((props, ref) => {
|
|
59
|
+
const { value = '00:00', start = '00:00', end = '23:59', bindchange } = props;
|
|
131
60
|
const nodeRef = useRef(null);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
const
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const [offsetTop, setOffsetTop] = useState(0);
|
|
140
|
-
const strStart = toStr(start);
|
|
141
|
-
const strEnd = toStr(end);
|
|
142
|
-
useEffect(() => {
|
|
143
|
-
const newColumnData = generateColumns();
|
|
144
|
-
setData(newColumnData);
|
|
145
|
-
}, [start, end]);
|
|
146
|
-
useEffect(() => {
|
|
147
|
-
if (value) {
|
|
148
|
-
const nValue = formatStrToInt(value);
|
|
149
|
-
nValue && setTimeValue(nValue);
|
|
150
|
-
}
|
|
151
|
-
}, [value]);
|
|
152
|
-
// console.log('---------------visible---', visible, JSON.stringify(columnData))
|
|
153
|
-
const handleModalStatus = (status) => {
|
|
154
|
-
setVisible(status);
|
|
61
|
+
const timerRef = useRef(null);
|
|
62
|
+
const startArray = time2Array(start);
|
|
63
|
+
const endArray = time2Array(end, [23, 59]);
|
|
64
|
+
const [formatValue, setFormatValue] = useState(calibrateTime(value, startArray, endArray));
|
|
65
|
+
const updateValue = (value = '00:00') => {
|
|
66
|
+
const calibratedValue = calibrateTime(value, startArray, endArray);
|
|
67
|
+
setFormatValue(calibratedValue);
|
|
155
68
|
};
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
69
|
+
const _props = useRef(props);
|
|
70
|
+
_props.current = props;
|
|
71
|
+
useImperativeHandle(ref, () => ({
|
|
72
|
+
updateValue,
|
|
73
|
+
getNodeInstance: () => ({
|
|
74
|
+
props: _props,
|
|
75
|
+
nodeRef,
|
|
76
|
+
instance: {
|
|
77
|
+
style: {}
|
|
161
78
|
}
|
|
162
|
-
})
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
79
|
+
})
|
|
80
|
+
}));
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
return () => {
|
|
83
|
+
timerRef.current && clearTimeout(timerRef.current);
|
|
84
|
+
};
|
|
85
|
+
}, []);
|
|
86
|
+
useUpdateEffect(() => {
|
|
87
|
+
const calibratedValue = calibrateTime(value, startArray, endArray);
|
|
88
|
+
setFormatValue(calibratedValue);
|
|
89
|
+
}, [value]);
|
|
90
|
+
const onChange = (e) => {
|
|
91
|
+
const { value } = e.detail;
|
|
92
|
+
const calibratedValue = calibrateTime(value, startArray, endArray);
|
|
93
|
+
bindchange?.({ detail: { value: time2String(calibratedValue) } });
|
|
94
|
+
if (value[0] !== formatValue[0] || value[1] !== formatValue[1]) {
|
|
95
|
+
setFormatValue(value);
|
|
175
96
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
97
|
+
if (value[0] !== calibratedValue[0] || value[1] !== calibratedValue[1]) {
|
|
98
|
+
timerRef.current && clearTimeout(timerRef.current);
|
|
99
|
+
timerRef.current = setTimeout(() => setFormatValue(calibratedValue));
|
|
179
100
|
}
|
|
180
101
|
};
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
});
|
|
192
|
-
};
|
|
193
|
-
const renderModalChildren = () => {
|
|
194
|
-
const pickerProps = {
|
|
195
|
-
ref: nodeRef,
|
|
196
|
-
data,
|
|
197
|
-
value: timevalue,
|
|
198
|
-
defaultValue: timevalue,
|
|
199
|
-
cols: 2,
|
|
200
|
-
onChange: handlePickChange
|
|
201
|
-
};
|
|
202
|
-
return (<View style={styles.centeredView} ref={modalRef} onLayout={onModalLayout}>
|
|
203
|
-
<View style={styles.btnLine}>
|
|
204
|
-
<View style={styles.cancel}>
|
|
205
|
-
<TouchableWithoutFeedback onPress={handleCancel}>
|
|
206
|
-
<Text style={styles.btntext}>取消</Text>
|
|
207
|
-
</TouchableWithoutFeedback>
|
|
208
|
-
</View>
|
|
209
|
-
<View style={styles.ok}>
|
|
210
|
-
<TouchableWithoutFeedback onPress={handleConfirm}>
|
|
211
|
-
<Text style={styles.btntext}>确定</Text>
|
|
212
|
-
</TouchableWithoutFeedback>
|
|
213
|
-
</View>
|
|
214
|
-
</View>
|
|
215
|
-
<PickerView {...pickerProps}></PickerView>
|
|
216
|
-
</View>);
|
|
217
|
-
};
|
|
218
|
-
const renderChildren = () => {
|
|
219
|
-
const touchProps = {
|
|
220
|
-
onLayout: onElementLayout,
|
|
221
|
-
ref: viewRef
|
|
222
|
-
};
|
|
223
|
-
return <View>
|
|
224
|
-
<TouchableWithoutFeedback onPress={handleChildClick}>
|
|
225
|
-
<View {...touchProps}>{children}</View>
|
|
226
|
-
</TouchableWithoutFeedback>
|
|
227
|
-
</View>;
|
|
228
|
-
};
|
|
229
|
-
// Animated.View
|
|
230
|
-
return (<>
|
|
231
|
-
<Portal>
|
|
232
|
-
<View style={visible ? styles.showModal : styles.hideModal}>
|
|
233
|
-
<Modal animationType="slide" transparent={true} visible={visible}>
|
|
234
|
-
{renderModalChildren()}
|
|
235
|
-
</Modal>
|
|
236
|
-
</View>
|
|
237
|
-
</Portal>
|
|
238
|
-
{renderChildren()}
|
|
239
|
-
</>);
|
|
102
|
+
return (<MpxPickerView style={styles.pickerContainer} indicator-style={styles.pickerIndicator} value={formatValue} bindchange={onChange}>
|
|
103
|
+
{/* @ts-expect-error ignore */}
|
|
104
|
+
<MpxPickerViewColumn key='hour'>
|
|
105
|
+
{hoursRange.map((item, index) => (<Text key={index} style={styles.pickerItem}>{item}</Text>))}
|
|
106
|
+
</MpxPickerViewColumn>
|
|
107
|
+
{/* @ts-expect-error ignore */}
|
|
108
|
+
<MpxPickerViewColumn key='minute'>
|
|
109
|
+
{minutesRange.map((item, index) => (<Text key={index} style={styles.pickerItem}>{item}</Text>))}
|
|
110
|
+
</MpxPickerViewColumn>
|
|
111
|
+
</MpxPickerView>);
|
|
240
112
|
});
|
|
241
|
-
|
|
242
|
-
export default
|
|
113
|
+
PickerTime.displayName = 'MpxPickerTime';
|
|
114
|
+
export default PickerTime;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { View } from 'react-native';
|
|
2
2
|
import React, { forwardRef, useRef } from 'react';
|
|
3
|
-
import useInnerProps, { getCustomEvent } from '
|
|
4
|
-
import useNodesRef from '
|
|
5
|
-
import { useLayout, splitProps, splitStyle, wrapChildren, useTransformStyle, extendObject } from '
|
|
3
|
+
import useInnerProps, { getCustomEvent } from '../getInnerListeners';
|
|
4
|
+
import useNodesRef from '../useNodesRef';
|
|
5
|
+
import { useLayout, splitProps, splitStyle, wrapChildren, useTransformStyle, extendObject } from '../utils';
|
|
6
6
|
import { PickerViewStyleContext } from './pickerVIewContext';
|
|
7
7
|
const styles = {
|
|
8
8
|
wrapper: {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import React, { forwardRef, useRef, useState, useMemo, useEffect, useCallback } from 'react';
|
|
2
2
|
import { StyleSheet, View } from 'react-native';
|
|
3
3
|
import Reanimated, { useAnimatedRef, useScrollViewOffset } from 'react-native-reanimated';
|
|
4
|
-
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS } from '
|
|
5
|
-
import useNodesRef from '
|
|
4
|
+
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS } from '../utils';
|
|
5
|
+
import useNodesRef from '../useNodesRef';
|
|
6
6
|
import PickerIndicator from './pickerViewIndicator';
|
|
7
7
|
import PickerMask from './pickerViewMask';
|
|
8
|
-
import MpxPickerVIewColumnItem from './
|
|
9
|
-
import { PickerViewColumnAnimationContext } from '
|
|
8
|
+
import MpxPickerVIewColumnItem from './pickerViewColumnItem';
|
|
9
|
+
import { PickerViewColumnAnimationContext } from '../mpx-picker-view/pickerVIewContext';
|
|
10
|
+
import { calcHeightOffsets } from './pickerViewFaces';
|
|
10
11
|
const visibleCount = 5;
|
|
11
12
|
const _PickerViewColumn = forwardRef((props, ref) => {
|
|
12
13
|
const { columnData, columnIndex, initialIndex, onSelectChange, style, wrapperStyle, pickerMaskStyle, pickerIndicatorStyle, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
|
|
@@ -22,10 +23,11 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
22
23
|
const [itemRawH, setItemRawH] = useState(itemHeight);
|
|
23
24
|
const maxIndex = useMemo(() => columnData.length - 1, [columnData]);
|
|
24
25
|
const prevScrollingInfo = useRef({ index: initialIndex, y: 0 });
|
|
25
|
-
const
|
|
26
|
+
const dragging = useRef(false);
|
|
26
27
|
const scrolling = useRef(false);
|
|
27
28
|
const timerResetPosition = useRef(null);
|
|
28
29
|
const timerScrollTo = useRef(null);
|
|
30
|
+
const timerClickOnce = useRef(null);
|
|
29
31
|
const activeIndex = useRef(initialIndex);
|
|
30
32
|
const prevIndex = usePrevious(initialIndex);
|
|
31
33
|
const prevMaxIndex = usePrevious(maxIndex);
|
|
@@ -57,6 +59,12 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
57
59
|
timerScrollTo.current = null;
|
|
58
60
|
}
|
|
59
61
|
}, []);
|
|
62
|
+
const clearTimerClickOnce = useCallback(() => {
|
|
63
|
+
if (timerClickOnce.current) {
|
|
64
|
+
clearTimeout(timerClickOnce.current);
|
|
65
|
+
timerClickOnce.current = null;
|
|
66
|
+
}
|
|
67
|
+
}, []);
|
|
60
68
|
useEffect(() => {
|
|
61
69
|
return () => {
|
|
62
70
|
clearTimerResetPosition();
|
|
@@ -66,7 +74,7 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
66
74
|
useEffect(() => {
|
|
67
75
|
if (!scrollViewRef.current ||
|
|
68
76
|
!itemRawH ||
|
|
69
|
-
|
|
77
|
+
dragging.current ||
|
|
70
78
|
scrolling.current ||
|
|
71
79
|
prevIndex == null ||
|
|
72
80
|
initialIndex === prevIndex ||
|
|
@@ -81,8 +89,8 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
81
89
|
y: initialIndex * itemRawH,
|
|
82
90
|
animated: false
|
|
83
91
|
});
|
|
84
|
-
|
|
85
|
-
|
|
92
|
+
activeIndex.current = initialIndex;
|
|
93
|
+
}, isIOS ? 0 : 200);
|
|
86
94
|
}, [itemRawH, maxIndex, initialIndex]);
|
|
87
95
|
const onContentSizeChange = useCallback((_w, h) => {
|
|
88
96
|
const y = initialIndex * itemRawH;
|
|
@@ -90,6 +98,7 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
90
98
|
clearTimerScrollTo();
|
|
91
99
|
timerScrollTo.current = setTimeout(() => {
|
|
92
100
|
scrollViewRef.current?.scrollTo({ x: 0, y, animated: false });
|
|
101
|
+
activeIndex.current = initialIndex;
|
|
93
102
|
}, 0);
|
|
94
103
|
}
|
|
95
104
|
}, [itemRawH, initialIndex]);
|
|
@@ -101,7 +110,7 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
101
110
|
}
|
|
102
111
|
}, [itemRawH]);
|
|
103
112
|
const resetScrollPosition = useCallback((y) => {
|
|
104
|
-
if (
|
|
113
|
+
if (dragging.current || scrolling.current) {
|
|
105
114
|
return;
|
|
106
115
|
}
|
|
107
116
|
scrolling.current = true;
|
|
@@ -126,14 +135,14 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
126
135
|
}, [itemRawH, getIndex, onSelectChange, resetScrollPosition]);
|
|
127
136
|
const onScrollBeginDrag = useCallback(() => {
|
|
128
137
|
isIOS && clearTimerResetPosition();
|
|
129
|
-
|
|
138
|
+
dragging.current = true;
|
|
130
139
|
prevScrollingInfo.current = {
|
|
131
140
|
index: activeIndex.current,
|
|
132
141
|
y: activeIndex.current * itemRawH
|
|
133
142
|
};
|
|
134
143
|
}, [itemRawH]);
|
|
135
144
|
const onScrollEndDrag = useCallback((e) => {
|
|
136
|
-
|
|
145
|
+
dragging.current = false;
|
|
137
146
|
if (isIOS) {
|
|
138
147
|
const { y } = e.nativeEvent.contentOffset;
|
|
139
148
|
if (y % itemRawH === 0) {
|
|
@@ -154,7 +163,7 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
154
163
|
}
|
|
155
164
|
const { y } = e.nativeEvent.contentOffset;
|
|
156
165
|
const { index: prevIndex, y: _y } = prevScrollingInfo.current;
|
|
157
|
-
if (
|
|
166
|
+
if (dragging.current || scrolling.current) {
|
|
158
167
|
if (Math.abs(y - _y) >= itemRawH) {
|
|
159
168
|
const currentId = getIndex(y);
|
|
160
169
|
if (currentId !== prevIndex) {
|
|
@@ -168,12 +177,51 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
168
177
|
}
|
|
169
178
|
}
|
|
170
179
|
}, [itemRawH, getIndex]);
|
|
180
|
+
const offsetHeights = useMemo(() => calcHeightOffsets(itemRawH), [itemRawH]);
|
|
181
|
+
const calcOffset = useCallback((y) => {
|
|
182
|
+
const baselineY = activeIndex.current * itemRawH + pickerH / 2;
|
|
183
|
+
const diff = Math.abs(y - baselineY);
|
|
184
|
+
const positive = y - baselineY > 0 ? 1 : -1;
|
|
185
|
+
const [h1, h2, h3] = offsetHeights;
|
|
186
|
+
if (diff > h1 && diff < h3) {
|
|
187
|
+
if (diff < h2) {
|
|
188
|
+
return 1 * positive;
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
return 2 * positive;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
}, [offsetHeights]);
|
|
196
|
+
/**
|
|
197
|
+
* 和小程序表现对齐,点击(不滑动)非焦点选项自动滚动到对应位置
|
|
198
|
+
*/
|
|
199
|
+
const onClickOnceItem = useCallback((e) => {
|
|
200
|
+
const { locationY } = e.nativeEvent || {};
|
|
201
|
+
const offsetIndex = calcOffset(locationY);
|
|
202
|
+
if (dragging.current || !offsetIndex) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const targetIndex = activeIndex.current + offsetIndex;
|
|
206
|
+
if (targetIndex < 0 || targetIndex > maxIndex) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const y = targetIndex * itemRawH;
|
|
210
|
+
scrollViewRef.current?.scrollTo({ x: 0, y, animated: true });
|
|
211
|
+
if (isAndroid) {
|
|
212
|
+
// Android scrollTo 不会自动触发 onMomentumScrollEnd,需要手动触发
|
|
213
|
+
clearTimerClickOnce();
|
|
214
|
+
timerClickOnce.current = setTimeout(() => {
|
|
215
|
+
onMomentumScrollEnd({ nativeEvent: { contentOffset: { y } } });
|
|
216
|
+
}, 250);
|
|
217
|
+
}
|
|
218
|
+
}, [itemRawH, maxIndex, calcOffset, onMomentumScrollEnd]);
|
|
171
219
|
const renderInnerchild = () => columnData.map((item, index) => {
|
|
172
220
|
return (<MpxPickerVIewColumnItem key={index} item={item} index={index} itemHeight={itemHeight} textStyle={textStyle} textProps={textProps} visibleCount={visibleCount} onItemLayout={onItemLayout}/>);
|
|
173
221
|
});
|
|
174
222
|
const renderScollView = () => {
|
|
175
223
|
return (<PickerViewColumnAnimationContext.Provider value={offsetYShared}>
|
|
176
|
-
<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}>
|
|
224
|
+
<Reanimated.ScrollView ref={scrollViewRef} bounces={true} horizontal={false} nestedScrollEnabled={true} removeClippedSubviews={false} showsVerticalScrollIndicator={false} showsHorizontalScrollIndicator={false} scrollEventThrottle={16} {...layoutProps} onTouchStart={onClickOnceItem} style={[{ width: '100%' }]} decelerationRate="fast" snapToOffsets={snapToOffsets} onScroll={onScroll} onScrollBeginDrag={onScrollBeginDrag} onScrollEndDrag={onScrollEndDrag} onMomentumScrollBegin={onMomentumScrollBegin} onMomentumScrollEnd={onMomentumScrollEnd} onContentSizeChange={onContentSizeChange} contentContainerStyle={contentContainerStyle}>
|
|
177
225
|
{renderInnerchild()}
|
|
178
226
|
</Reanimated.ScrollView>
|
|
179
227
|
</PickerViewColumnAnimationContext.Provider>);
|
|
@@ -181,9 +229,9 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
181
229
|
const renderIndicator = () => (<PickerIndicator itemHeight={itemHeight} indicatorItemStyle={pickerIndicatorStyle}/>);
|
|
182
230
|
const renderMask = () => (<PickerMask itemHeight={itemHeight} maskContainerStyle={pickerMaskStyle}/>);
|
|
183
231
|
return (<View style={[styles.wrapper, normalStyle]}>
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
232
|
+
{renderScollView()}
|
|
233
|
+
{renderMask()}
|
|
234
|
+
{renderIndicator()}
|
|
187
235
|
</View>);
|
|
188
236
|
});
|
|
189
237
|
const styles = StyleSheet.create({
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { useEffect } from 'react';
|
|
2
2
|
import Reanimated, { Extrapolation, interpolate, useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
|
|
3
|
-
import { extendObject } from '
|
|
4
|
-
import { createFaces } from './
|
|
5
|
-
import { usePickerViewColumnAnimationContext, usePickerViewStyleContext } from '
|
|
3
|
+
import { extendObject } from '../utils';
|
|
4
|
+
import { createFaces } from './pickerViewFaces';
|
|
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();
|
|
@@ -27,8 +27,11 @@ const PickerViewColumnItem = ({ item, index, itemHeight, itemWidth = '100%', tex
|
|
|
27
27
|
style: extendObject({ height: itemHeight, width: '100%' }, textStyleFromAncestor, textStyle, item.props.style)
|
|
28
28
|
}, textProps, restProps);
|
|
29
29
|
const realItem = React.cloneElement(item, itemProps);
|
|
30
|
-
return (<Reanimated.View key={strKey} style={[
|
|
31
|
-
|
|
30
|
+
return (<Reanimated.View key={strKey} style={[
|
|
31
|
+
{ height: itemHeight, width: itemWidth, pointerEvents: 'none' },
|
|
32
|
+
animatedStyles
|
|
33
|
+
]}>
|
|
34
|
+
{realItem}
|
|
32
35
|
</Reanimated.View>);
|
|
33
36
|
};
|
|
34
37
|
PickerViewColumnItem.displayName = 'MpxPickerViewColumnItem';
|
|
@@ -11,6 +11,12 @@ export const calcPickerHeight = (faces, itemHeight) => {
|
|
|
11
11
|
}
|
|
12
12
|
return faces.reduce((r, v) => r + calcHeight(Math.abs(v.deg), itemHeight), 0);
|
|
13
13
|
};
|
|
14
|
+
export const calcHeightOffsets = (itemHeight) => {
|
|
15
|
+
const h1 = itemHeight / 2;
|
|
16
|
+
const h2 = h1 + calcHeight(30, itemHeight);
|
|
17
|
+
const h3 = h2 + calcHeight(60, itemHeight);
|
|
18
|
+
return [h1, h2, h3];
|
|
19
|
+
};
|
|
14
20
|
export const createFaces = (itemHeight, visibleCount) => {
|
|
15
21
|
// e.g [30, 60, 90]
|
|
16
22
|
const getDegreesRelativeCenter = () => {
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { cloneElement } from 'react';
|
|
2
|
+
import Portal from '../mpx-portal';
|
|
3
|
+
import PopupBase from './popupBase';
|
|
4
|
+
/**
|
|
5
|
+
* 根据 type 返回对应的弹窗壳子组件
|
|
6
|
+
*/
|
|
7
|
+
const getPopup = (type) => {
|
|
8
|
+
switch (type) {
|
|
9
|
+
case "picker" /* PopupType.PICKER */:
|
|
10
|
+
default:
|
|
11
|
+
return PopupBase;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* 基于 Portal 封装的 Popup 弹窗组件管理 Hooks
|
|
16
|
+
*/
|
|
17
|
+
const createPopupManager = (options = {}) => {
|
|
18
|
+
const { modal, type } = options;
|
|
19
|
+
const Modal = modal || getPopup(type);
|
|
20
|
+
let popupKey = null;
|
|
21
|
+
let isOpen = false;
|
|
22
|
+
let child = null;
|
|
23
|
+
const remove = () => {
|
|
24
|
+
if (popupKey !== null) {
|
|
25
|
+
Portal.remove(popupKey);
|
|
26
|
+
popupKey = null;
|
|
27
|
+
}
|
|
28
|
+
isOpen = false;
|
|
29
|
+
};
|
|
30
|
+
const open = (childComponent, pageId, options) => {
|
|
31
|
+
if (!isOpen && pageId != null) {
|
|
32
|
+
isOpen = true;
|
|
33
|
+
child = (<Modal hide={hide} {...options} visible={false}>
|
|
34
|
+
{childComponent}
|
|
35
|
+
</Modal>);
|
|
36
|
+
popupKey = Portal.add(child, pageId);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const update = (updatedChild) => {
|
|
40
|
+
if (popupKey !== null && child !== null && updatedChild !== null) {
|
|
41
|
+
child = cloneElement(child, { children: updatedChild });
|
|
42
|
+
Portal.update(popupKey, child);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const _updateVisible = (visible) => {
|
|
46
|
+
if (popupKey !== null && child !== null) {
|
|
47
|
+
child = cloneElement(child, { visible });
|
|
48
|
+
Portal.update(popupKey, child);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const show = () => _updateVisible(true);
|
|
52
|
+
const hide = () => _updateVisible(false);
|
|
53
|
+
return {
|
|
54
|
+
open,
|
|
55
|
+
show,
|
|
56
|
+
hide,
|
|
57
|
+
update,
|
|
58
|
+
remove
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
export { createPopupManager };
|