@mpxjs/webpack-plugin 2.10.3-beta.17 → 2.10.3-beta.18
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/runtime/components/react/dist/context.js +5 -1
- package/lib/runtime/components/react/dist/event.config.js +0 -1
- package/lib/runtime/components/react/dist/getInnerListeners.js +148 -149
- package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +145 -0
- package/lib/runtime/components/react/dist/mpx-button.jsx +11 -7
- package/lib/runtime/components/react/dist/mpx-canvas/Image.js +2 -4
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +23 -21
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +9 -4
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +9 -5
- package/lib/runtime/components/react/dist/mpx-form.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-icon/icons/cancel.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/clear.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/download.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/info.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/search.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/success.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/success_no_circle.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/waiting.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/warn.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/index.jsx +9 -4
- package/lib/runtime/components/react/dist/mpx-image.jsx +92 -41
- package/lib/runtime/components/react/dist/mpx-inline-text.jsx +11 -0
- package/lib/runtime/components/react/dist/mpx-input.jsx +14 -13
- package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +22 -7
- package/lib/runtime/components/react/dist/mpx-label.jsx +9 -5
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +10 -5
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +206 -80
- package/lib/runtime/components/react/dist/mpx-navigator.jsx +11 -3
- 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 -98
- 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} +16 -15
- package/lib/runtime/components/react/dist/{mpx-picker-view-column.jsx → mpx-picker-view-column/index.jsx} +95 -26
- package/lib/runtime/components/react/dist/{mpx-picker-view-column-item.jsx → mpx-picker-view-column/pickerViewColumnItem.jsx} +16 -16
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItemLite.jsx +20 -0
- 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-portal/index.jsx +5 -1
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +3 -5
- package/lib/runtime/components/react/dist/mpx-progress.jsx +163 -0
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +11 -4
- package/lib/runtime/components/react/dist/mpx-radio.jsx +9 -5
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +12 -4
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +317 -89
- package/lib/runtime/components/react/dist/mpx-simple-text.jsx +7 -5
- package/lib/runtime/components/react/dist/mpx-simple-view.jsx +11 -15
- package/lib/runtime/components/react/dist/mpx-slider.jsx +321 -0
- package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +117 -0
- package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +45 -0
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +15 -14
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +245 -121
- package/lib/runtime/components/react/dist/mpx-switch.jsx +10 -7
- package/lib/runtime/components/react/dist/mpx-text.jsx +43 -13
- package/lib/runtime/components/react/dist/mpx-video.jsx +12 -7
- package/lib/runtime/components/react/dist/mpx-view.jsx +34 -18
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +40 -35
- package/lib/runtime/components/react/dist/useAnimationHooks.js +35 -90
- package/lib/runtime/components/react/dist/utils.jsx +215 -109
- package/lib/runtime/components/web/mpx-titlebar.vue +21 -18
- package/package.json +1 -1
- /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
|
@@ -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,9 +1,10 @@
|
|
|
1
1
|
import { View } from 'react-native';
|
|
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 '
|
|
2
|
+
import React, { createElement, forwardRef, useRef } from 'react';
|
|
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
|
+
import Portal from '../mpx-portal';
|
|
7
8
|
const styles = {
|
|
8
9
|
wrapper: {
|
|
9
10
|
display: 'flex',
|
|
@@ -16,14 +17,14 @@ const styles = {
|
|
|
16
17
|
};
|
|
17
18
|
const DefaultPickerItemH = 36;
|
|
18
19
|
const _PickerView = forwardRef((props, ref) => {
|
|
19
|
-
const { children, value = [], bindchange, style, 'indicator-style': indicatorStyle = {}, 'mask-style': pickerMaskStyle = {}, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
|
|
20
|
+
const { children, value = [], bindchange, style, 'enable-wheel-animation': enableWheelAnimation = true, 'indicator-style': indicatorStyle = {}, 'mask-style': pickerMaskStyle = {}, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
|
|
20
21
|
const { height: indicatorH, ...pickerIndicatorStyle } = indicatorStyle;
|
|
21
22
|
const nodeRef = useRef(null);
|
|
22
23
|
const cloneRef = useRef(null);
|
|
23
24
|
const activeValueRef = useRef(value);
|
|
24
25
|
activeValueRef.current = value.slice();
|
|
25
26
|
const snapActiveValueRef = useRef(null);
|
|
26
|
-
const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext });
|
|
27
|
+
const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight, hasPositionFixed } = useTransformStyle(style, { enableVar, externalVarContext });
|
|
27
28
|
useNodesRef(props, ref, nodeRef, {
|
|
28
29
|
style: normalStyle
|
|
29
30
|
});
|
|
@@ -47,13 +48,12 @@ const _PickerView = forwardRef((props, ref) => {
|
|
|
47
48
|
snapActiveValueRef.current = value.slice();
|
|
48
49
|
}
|
|
49
50
|
};
|
|
50
|
-
const innerProps = useInnerProps(props,
|
|
51
|
+
const innerProps = useInnerProps(extendObject({}, props, layoutProps, {
|
|
51
52
|
ref: nodeRef,
|
|
52
53
|
style: extendObject({}, normalStyle, layoutStyle, {
|
|
53
54
|
position: 'relative',
|
|
54
55
|
overflow: 'hidden'
|
|
55
|
-
})
|
|
56
|
-
layoutProps
|
|
56
|
+
})
|
|
57
57
|
}), [
|
|
58
58
|
'enable-offset',
|
|
59
59
|
'indicator-style',
|
|
@@ -75,7 +75,8 @@ const _PickerView = forwardRef((props, ref) => {
|
|
|
75
75
|
onSelectChange: onSelectChange.bind(null, index),
|
|
76
76
|
initialIndex,
|
|
77
77
|
pickerIndicatorStyle,
|
|
78
|
-
pickerMaskStyle
|
|
78
|
+
pickerMaskStyle,
|
|
79
|
+
enableWheelAnimation
|
|
79
80
|
});
|
|
80
81
|
const realElement = React.cloneElement(child, wrappedProps);
|
|
81
82
|
return wrapChildren({
|
|
@@ -115,11 +116,11 @@ const _PickerView = forwardRef((props, ref) => {
|
|
|
115
116
|
onInitialChange(isInvalid, validValue);
|
|
116
117
|
return renderColumns;
|
|
117
118
|
};
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
const finalComponent = createElement(PickerViewStyleContext.Provider, { value: textStyle }, createElement(View, innerProps, createElement(View, { style: [styles.wrapper] }, renderPickerColumns())));
|
|
120
|
+
if (hasPositionFixed) {
|
|
121
|
+
return createElement(Portal, null, finalComponent);
|
|
122
|
+
}
|
|
123
|
+
return finalComponent;
|
|
123
124
|
});
|
|
124
125
|
_PickerView.displayName = 'MpxPickerView';
|
|
125
126
|
export default _PickerView;
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import React, { forwardRef, useRef, useState, useMemo, useEffect, useCallback } from 'react';
|
|
1
|
+
import React, { forwardRef, useRef, useState, useMemo, useEffect, useCallback, createElement } 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, isHarmony } from '
|
|
5
|
-
import useNodesRef from '
|
|
4
|
+
import { useTransformStyle, splitStyle, splitProps, useLayout, usePrevious, isAndroid, isIOS, isHarmony, extendObject } from '../utils';
|
|
5
|
+
import useNodesRef from '../useNodesRef';
|
|
6
6
|
import PickerIndicator from './pickerViewIndicator';
|
|
7
7
|
import PickerMask from './pickerViewMask';
|
|
8
|
-
import
|
|
9
|
-
import
|
|
8
|
+
import MpxPickerViewColumnItem from './pickerViewColumnItem';
|
|
9
|
+
import MpxPickerViewColumnItemLite from './pickerViewColumnItemLite';
|
|
10
|
+
import { PickerViewColumnAnimationContext } from '../mpx-picker-view/pickerVIewContext';
|
|
11
|
+
import { calcHeightOffsets } from './pickerViewFaces';
|
|
10
12
|
const visibleCount = 5;
|
|
11
13
|
const _PickerViewColumn = forwardRef((props, ref) => {
|
|
12
|
-
const { columnData, columnIndex, initialIndex, onSelectChange, style, wrapperStyle, pickerMaskStyle, pickerIndicatorStyle, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
|
|
14
|
+
const { columnData, columnIndex, initialIndex, onSelectChange, style, wrapperStyle, pickerMaskStyle, pickerIndicatorStyle, enableWheelAnimation = true, 'enable-var': enableVar, 'external-var-context': externalVarContext } = props;
|
|
13
15
|
const { normalStyle, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext });
|
|
14
16
|
const { textStyle = {} } = splitStyle(normalStyle);
|
|
15
17
|
const { textProps = {} } = splitProps(props);
|
|
@@ -22,10 +24,11 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
22
24
|
const [itemRawH, setItemRawH] = useState(itemHeight);
|
|
23
25
|
const maxIndex = useMemo(() => columnData.length - 1, [columnData]);
|
|
24
26
|
const prevScrollingInfo = useRef({ index: initialIndex, y: 0 });
|
|
25
|
-
const
|
|
27
|
+
const dragging = useRef(false);
|
|
26
28
|
const scrolling = useRef(false);
|
|
27
29
|
const timerResetPosition = useRef(null);
|
|
28
30
|
const timerScrollTo = useRef(null);
|
|
31
|
+
const timerClickOnce = useRef(null);
|
|
29
32
|
const activeIndex = useRef(initialIndex);
|
|
30
33
|
const prevIndex = usePrevious(initialIndex);
|
|
31
34
|
const prevMaxIndex = usePrevious(maxIndex);
|
|
@@ -57,6 +60,12 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
57
60
|
timerScrollTo.current = null;
|
|
58
61
|
}
|
|
59
62
|
}, []);
|
|
63
|
+
const clearTimerClickOnce = useCallback(() => {
|
|
64
|
+
if (timerClickOnce.current) {
|
|
65
|
+
clearTimeout(timerClickOnce.current);
|
|
66
|
+
timerClickOnce.current = null;
|
|
67
|
+
}
|
|
68
|
+
}, []);
|
|
60
69
|
useEffect(() => {
|
|
61
70
|
return () => {
|
|
62
71
|
clearTimerResetPosition();
|
|
@@ -66,7 +75,7 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
66
75
|
useEffect(() => {
|
|
67
76
|
if (!scrollViewRef.current ||
|
|
68
77
|
!itemRawH ||
|
|
69
|
-
|
|
78
|
+
dragging.current ||
|
|
70
79
|
scrolling.current ||
|
|
71
80
|
prevIndex == null ||
|
|
72
81
|
initialIndex === prevIndex ||
|
|
@@ -81,8 +90,8 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
81
90
|
y: initialIndex * itemRawH,
|
|
82
91
|
animated: false
|
|
83
92
|
});
|
|
84
|
-
|
|
85
|
-
|
|
93
|
+
activeIndex.current = initialIndex;
|
|
94
|
+
}, isIOS ? 0 : 200);
|
|
86
95
|
}, [itemRawH, maxIndex, initialIndex]);
|
|
87
96
|
const onContentSizeChange = useCallback((_w, h) => {
|
|
88
97
|
const y = initialIndex * itemRawH;
|
|
@@ -90,6 +99,7 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
90
99
|
clearTimerScrollTo();
|
|
91
100
|
timerScrollTo.current = setTimeout(() => {
|
|
92
101
|
scrollViewRef.current?.scrollTo({ x: 0, y, animated: false });
|
|
102
|
+
activeIndex.current = initialIndex;
|
|
93
103
|
}, 0);
|
|
94
104
|
}
|
|
95
105
|
}, [itemRawH, initialIndex]);
|
|
@@ -101,7 +111,7 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
101
111
|
}
|
|
102
112
|
}, [itemRawH]);
|
|
103
113
|
const resetScrollPosition = useCallback((y) => {
|
|
104
|
-
if (
|
|
114
|
+
if (dragging.current || scrolling.current) {
|
|
105
115
|
return;
|
|
106
116
|
}
|
|
107
117
|
scrolling.current = true;
|
|
@@ -126,17 +136,17 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
126
136
|
}, [itemRawH, getIndex, onSelectChange, resetScrollPosition]);
|
|
127
137
|
const onScrollBeginDrag = useCallback(() => {
|
|
128
138
|
isIOS && clearTimerResetPosition();
|
|
129
|
-
|
|
139
|
+
dragging.current = true;
|
|
130
140
|
prevScrollingInfo.current = {
|
|
131
141
|
index: activeIndex.current,
|
|
132
142
|
y: activeIndex.current * itemRawH
|
|
133
143
|
};
|
|
134
144
|
}, [itemRawH]);
|
|
135
145
|
const onScrollEndDrag = useCallback((e) => {
|
|
136
|
-
|
|
137
|
-
if (
|
|
146
|
+
dragging.current = false;
|
|
147
|
+
if (!isAndroid) {
|
|
138
148
|
const { y } = e.nativeEvent.contentOffset;
|
|
139
|
-
if (y % itemRawH === 0) {
|
|
149
|
+
if (y % itemRawH === 0 || (isHarmony && y > snapToOffsets[maxIndex])) {
|
|
140
150
|
onMomentumScrollEnd({ nativeEvent: { contentOffset: { y } } });
|
|
141
151
|
}
|
|
142
152
|
else if (y > 0 && y < snapToOffsets[maxIndex]) {
|
|
@@ -148,13 +158,13 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
148
158
|
}, [itemRawH, maxIndex, snapToOffsets, onMomentumScrollEnd, resetScrollPosition]);
|
|
149
159
|
const onScroll = useCallback((e) => {
|
|
150
160
|
// 全局注册的振动触感 hook
|
|
151
|
-
const
|
|
152
|
-
if (typeof
|
|
161
|
+
const onPickerVibrate = global.__mpx?.config?.rnConfig?.onPickerVibrate;
|
|
162
|
+
if (typeof onPickerVibrate !== 'function') {
|
|
153
163
|
return;
|
|
154
164
|
}
|
|
155
165
|
const { y } = e.nativeEvent.contentOffset;
|
|
156
166
|
const { index: prevIndex, y: _y } = prevScrollingInfo.current;
|
|
157
|
-
if (
|
|
167
|
+
if (dragging.current || scrolling.current) {
|
|
158
168
|
if (Math.abs(y - _y) >= itemRawH) {
|
|
159
169
|
const currentId = getIndex(y);
|
|
160
170
|
if (currentId !== prevIndex) {
|
|
@@ -163,20 +173,78 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
163
173
|
y: currentId * itemRawH
|
|
164
174
|
};
|
|
165
175
|
// vibrateShort({ type: 'selection' })
|
|
166
|
-
|
|
176
|
+
onPickerVibrate();
|
|
167
177
|
}
|
|
168
178
|
}
|
|
169
179
|
}
|
|
170
180
|
}, [itemRawH, getIndex]);
|
|
181
|
+
const offsetHeights = useMemo(() => calcHeightOffsets(itemRawH), [itemRawH]);
|
|
182
|
+
const calcOffset = useCallback((y) => {
|
|
183
|
+
const baselineY = activeIndex.current * itemRawH + pickerH / 2;
|
|
184
|
+
const diff = Math.abs(y - baselineY);
|
|
185
|
+
const positive = y - baselineY > 0 ? 1 : -1;
|
|
186
|
+
const [h1, h2, h3] = offsetHeights;
|
|
187
|
+
if (diff > h1 && diff < h3) {
|
|
188
|
+
if (diff < h2) {
|
|
189
|
+
return 1 * positive;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
return 2 * positive;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return false;
|
|
196
|
+
}, [offsetHeights]);
|
|
197
|
+
/**
|
|
198
|
+
* 和小程序表现对齐,点击(不滑动)非焦点选项自动滚动到对应位置
|
|
199
|
+
*/
|
|
200
|
+
const onClickOnceItem = useCallback((e) => {
|
|
201
|
+
const { locationY } = e.nativeEvent || {};
|
|
202
|
+
const offsetIndex = calcOffset(locationY);
|
|
203
|
+
if (dragging.current || !offsetIndex) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const targetIndex = activeIndex.current + offsetIndex;
|
|
207
|
+
if (targetIndex < 0 || targetIndex > maxIndex) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const y = targetIndex * itemRawH;
|
|
211
|
+
scrollViewRef.current?.scrollTo({ x: 0, y, animated: true });
|
|
212
|
+
if (isAndroid) {
|
|
213
|
+
// Android scrollTo 不会自动触发 onMomentumScrollEnd,需要手动触发
|
|
214
|
+
clearTimerClickOnce();
|
|
215
|
+
timerClickOnce.current = setTimeout(() => {
|
|
216
|
+
onMomentumScrollEnd({ nativeEvent: { contentOffset: { y } } });
|
|
217
|
+
}, 250);
|
|
218
|
+
}
|
|
219
|
+
}, [itemRawH, maxIndex, calcOffset, onMomentumScrollEnd]);
|
|
171
220
|
const renderInnerchild = () => columnData.map((item, index) => {
|
|
172
|
-
return
|
|
221
|
+
return enableWheelAnimation
|
|
222
|
+
? (<MpxPickerViewColumnItem key={index} item={item} index={index} itemHeight={itemHeight} textStyle={textStyle} textProps={textProps} visibleCount={visibleCount} onItemLayout={onItemLayout}/>)
|
|
223
|
+
: (<MpxPickerViewColumnItemLite key={index} item={item} index={index} itemHeight={itemHeight} textStyle={textStyle} textProps={textProps} onItemLayout={onItemLayout}/>);
|
|
173
224
|
});
|
|
174
225
|
const renderScollView = () => {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
226
|
+
const innerProps = extendObject({}, layoutProps, {
|
|
227
|
+
ref: scrollViewRef,
|
|
228
|
+
bounces: true,
|
|
229
|
+
horizontal: false,
|
|
230
|
+
nestedScrollEnabled: true,
|
|
231
|
+
removeClippedSubviews: false,
|
|
232
|
+
showsVerticalScrollIndicator: false,
|
|
233
|
+
showsHorizontalScrollIndicator: false,
|
|
234
|
+
scrollEventThrottle: 16,
|
|
235
|
+
style: styles.scrollView,
|
|
236
|
+
decelerationRate: 'fast',
|
|
237
|
+
snapToOffsets: snapToOffsets,
|
|
238
|
+
onTouchEnd: onClickOnceItem,
|
|
239
|
+
onScroll,
|
|
240
|
+
onScrollBeginDrag,
|
|
241
|
+
onScrollEndDrag,
|
|
242
|
+
onMomentumScrollBegin,
|
|
243
|
+
onMomentumScrollEnd,
|
|
244
|
+
onContentSizeChange,
|
|
245
|
+
contentContainerStyle
|
|
246
|
+
});
|
|
247
|
+
return createElement(PickerViewColumnAnimationContext.Provider, { value: offsetYShared }, createElement(Reanimated.ScrollView, innerProps, renderInnerchild()));
|
|
180
248
|
};
|
|
181
249
|
const renderIndicator = () => (<PickerIndicator itemHeight={itemHeight} indicatorItemStyle={pickerIndicatorStyle}/>);
|
|
182
250
|
const renderMask = () => (<PickerMask itemHeight={itemHeight} maskContainerStyle={pickerMaskStyle}/>);
|
|
@@ -187,7 +255,8 @@ const _PickerViewColumn = forwardRef((props, ref) => {
|
|
|
187
255
|
</View>);
|
|
188
256
|
});
|
|
189
257
|
const styles = StyleSheet.create({
|
|
190
|
-
wrapper: { display: 'flex', flex: 1 }
|
|
258
|
+
wrapper: { display: 'flex', flex: 1 },
|
|
259
|
+
scrollView: { width: '100%' }
|
|
191
260
|
});
|
|
192
261
|
_PickerViewColumn.displayName = 'MpxPickerViewColumn';
|
|
193
262
|
export default _PickerViewColumn;
|