react-native-dates-picker 0.0.8 → 0.1.0
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/commonjs/CalendarContext.js.map +1 -1
- package/lib/commonjs/DateTimePicker.js +6 -1
- package/lib/commonjs/DateTimePicker.js.map +1 -1
- package/lib/commonjs/components/Calendar.js +1 -1
- package/lib/commonjs/components/Calendar.js.map +1 -1
- package/lib/commonjs/components/DatePicker.js +31 -27
- package/lib/commonjs/components/DatePicker.js.map +1 -1
- package/lib/commonjs/components/Day.js +11 -10
- package/lib/commonjs/components/Day.js.map +1 -1
- package/lib/commonjs/components/DaySelector.js +1 -1
- package/lib/commonjs/components/DaySelector.js.map +1 -1
- package/lib/commonjs/components/Header.js.map +1 -1
- package/lib/commonjs/components/MonthSelector.js.map +1 -1
- package/lib/commonjs/components/TimeSelector.js +6 -3
- package/lib/commonjs/components/TimeSelector.js.map +1 -1
- package/lib/commonjs/components/WheelPicker/Wheel.js +9 -5
- package/lib/commonjs/components/WheelPicker/Wheel.js.map +1 -1
- package/lib/commonjs/components/WheelPicker/WheelNative.js +16 -38
- package/lib/commonjs/components/WheelPicker/WheelNative.js.map +1 -1
- package/lib/commonjs/components/WheelPicker/WheelNativePicker/index.js +10 -0
- package/lib/commonjs/components/WheelPicker/WheelNativePicker/index.js.map +1 -0
- package/lib/commonjs/components/WheelPicker/WheelNativePicker/wheel-picker-item.js +124 -0
- package/lib/commonjs/components/WheelPicker/WheelNativePicker/wheel-picker-item.js.map +1 -0
- package/lib/commonjs/components/WheelPicker/WheelNativePicker/wheel-picker.js +169 -0
- package/lib/commonjs/components/WheelPicker/WheelNativePicker/wheel-picker.js.map +1 -0
- package/lib/commonjs/components/WheelPicker/WheelWeb.js +43 -38
- package/lib/commonjs/components/WheelPicker/WheelWeb.js.map +1 -1
- package/lib/commonjs/components/WheelPicker/animated-math.js +26 -0
- package/lib/commonjs/components/WheelPicker/animated-math.js.map +1 -0
- package/lib/commonjs/components/WheelPicker/period-native.js +36 -0
- package/lib/commonjs/components/WheelPicker/period-native.js.map +1 -0
- package/lib/commonjs/components/WheelPicker/period-picker.js +19 -0
- package/lib/commonjs/components/WheelPicker/period-picker.js.map +1 -0
- package/lib/commonjs/components/WheelPicker/period-web.js +34 -0
- package/lib/commonjs/components/WheelPicker/period-web.js.map +1 -0
- package/lib/commonjs/components/YearSelector.js.map +1 -1
- package/lib/commonjs/enums.js +5 -4
- package/lib/commonjs/enums.js.map +1 -1
- package/lib/commonjs/utils.js +4 -1
- package/lib/commonjs/utils.js.map +1 -1
- package/lib/module/CalendarContext.js.map +1 -1
- package/lib/module/DateTimePicker.js +6 -1
- package/lib/module/DateTimePicker.js.map +1 -1
- package/lib/module/components/Calendar.js +2 -2
- package/lib/module/components/Calendar.js.map +1 -1
- package/lib/module/components/DatePicker.js +32 -28
- package/lib/module/components/DatePicker.js.map +1 -1
- package/lib/module/components/Day.js +10 -10
- package/lib/module/components/Day.js.map +1 -1
- package/lib/module/components/DaySelector.js +1 -1
- package/lib/module/components/DaySelector.js.map +1 -1
- package/lib/module/components/Header.js.map +1 -1
- package/lib/module/components/MonthSelector.js.map +1 -1
- package/lib/module/components/TimeSelector.js +7 -4
- package/lib/module/components/TimeSelector.js.map +1 -1
- package/lib/module/components/WheelPicker/Wheel.js +6 -4
- package/lib/module/components/WheelPicker/Wheel.js.map +1 -1
- package/lib/module/components/WheelPicker/WheelNative.js +12 -36
- package/lib/module/components/WheelPicker/WheelNative.js.map +1 -1
- package/lib/module/components/WheelPicker/WheelNativePicker/index.js +3 -0
- package/lib/module/components/WheelPicker/WheelNativePicker/index.js.map +1 -0
- package/lib/module/components/WheelPicker/WheelNativePicker/wheel-picker-item.js +116 -0
- package/lib/module/components/WheelPicker/WheelNativePicker/wheel-picker-item.js.map +1 -0
- package/lib/module/components/WheelPicker/WheelNativePicker/wheel-picker.js +160 -0
- package/lib/module/components/WheelPicker/WheelNativePicker/wheel-picker.js.map +1 -0
- package/lib/module/components/WheelPicker/WheelWeb.js +44 -39
- package/lib/module/components/WheelPicker/WheelWeb.js.map +1 -1
- package/lib/module/components/WheelPicker/animated-math.js +20 -0
- package/lib/module/components/WheelPicker/animated-math.js.map +1 -0
- package/lib/module/components/WheelPicker/period-native.js +27 -0
- package/lib/module/components/WheelPicker/period-native.js.map +1 -0
- package/lib/module/components/WheelPicker/period-picker.js +10 -0
- package/lib/module/components/WheelPicker/period-picker.js.map +1 -0
- package/lib/module/components/WheelPicker/period-web.js +26 -0
- package/lib/module/components/WheelPicker/period-web.js.map +1 -0
- package/lib/module/components/YearSelector.js.map +1 -1
- package/lib/module/enums.js +4 -3
- package/lib/module/enums.js.map +1 -1
- package/lib/module/utils.js +4 -1
- package/lib/module/utils.js.map +1 -1
- package/lib/typescript/CalendarContext.d.ts.map +1 -1
- package/lib/typescript/DateTimePicker.d.ts +1 -1
- package/lib/typescript/DateTimePicker.d.ts.map +1 -1
- package/lib/typescript/components/Calendar.d.ts +1 -1
- package/lib/typescript/components/DatePicker.d.ts +2 -2
- package/lib/typescript/components/DatePicker.d.ts.map +1 -1
- package/lib/typescript/components/Day.d.ts +1 -2
- package/lib/typescript/components/Day.d.ts.map +1 -1
- package/lib/typescript/components/DaySelector.d.ts +2 -2
- package/lib/typescript/components/DaySelector.d.ts.map +1 -1
- package/lib/typescript/components/Header.d.ts +2 -2
- package/lib/typescript/components/Header.d.ts.map +1 -1
- package/lib/typescript/components/MonthSelector.d.ts +2 -2
- package/lib/typescript/components/MonthSelector.d.ts.map +1 -1
- package/lib/typescript/components/TimeSelector.d.ts +2 -2
- package/lib/typescript/components/TimeSelector.d.ts.map +1 -1
- package/lib/typescript/components/WheelPicker/Wheel.d.ts +5 -4
- package/lib/typescript/components/WheelPicker/Wheel.d.ts.map +1 -1
- package/lib/typescript/components/WheelPicker/WheelNative.d.ts +7 -8
- package/lib/typescript/components/WheelPicker/WheelNative.d.ts.map +1 -1
- package/lib/typescript/components/WheelPicker/WheelNativePicker/index.d.ts +3 -0
- package/lib/typescript/components/WheelPicker/WheelNativePicker/index.d.ts.map +1 -0
- package/lib/typescript/components/WheelPicker/WheelNativePicker/wheel-picker-item.d.ts +16 -0
- package/lib/typescript/components/WheelPicker/WheelNativePicker/wheel-picker-item.d.ts.map +1 -0
- package/lib/typescript/components/WheelPicker/WheelNativePicker/wheel-picker.d.ts +20 -0
- package/lib/typescript/components/WheelPicker/WheelNativePicker/wheel-picker.d.ts.map +1 -0
- package/lib/typescript/components/WheelPicker/WheelWeb.d.ts +5 -4
- package/lib/typescript/components/WheelPicker/WheelWeb.d.ts.map +1 -1
- package/lib/typescript/components/WheelPicker/animated-math.d.ts +5 -0
- package/lib/typescript/components/WheelPicker/animated-math.d.ts.map +1 -0
- package/lib/typescript/components/WheelPicker/period-native.d.ts +8 -0
- package/lib/typescript/components/WheelPicker/period-native.d.ts.map +1 -0
- package/lib/typescript/components/WheelPicker/period-picker.d.ts +8 -0
- package/lib/typescript/components/WheelPicker/period-picker.d.ts.map +1 -0
- package/lib/typescript/components/WheelPicker/period-web.d.ts +8 -0
- package/lib/typescript/components/WheelPicker/period-web.d.ts.map +1 -0
- package/lib/typescript/components/YearSelector.d.ts +2 -2
- package/lib/typescript/components/YearSelector.d.ts.map +1 -1
- package/lib/typescript/enums.d.ts +2 -1
- package/lib/typescript/enums.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +4 -0
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/utils.d.ts +2 -2
- package/lib/typescript/utils.d.ts.map +1 -1
- package/package.json +7 -6
- package/src/DateTimePicker.tsx +13 -8
- package/src/components/Calendar.tsx +4 -4
- package/src/components/DatePicker.tsx +33 -42
- package/src/components/Day.tsx +10 -10
- package/src/components/DaySelector.tsx +2 -2
- package/src/components/Header.tsx +1 -1
- package/src/components/MonthSelector.tsx +1 -1
- package/src/components/TimeSelector.tsx +8 -9
- package/src/components/WheelPicker/Wheel.tsx +9 -9
- package/src/components/WheelPicker/WheelNative.tsx +17 -39
- package/src/components/WheelPicker/WheelNativePicker/index.ts +3 -0
- package/src/components/WheelPicker/WheelNativePicker/wheel-picker-item.tsx +137 -0
- package/src/components/WheelPicker/WheelNativePicker/wheel-picker.tsx +214 -0
- package/src/components/WheelPicker/WheelWeb.tsx +83 -64
- package/src/components/WheelPicker/animated-math.ts +33 -0
- package/src/components/WheelPicker/period-native.tsx +39 -0
- package/src/components/WheelPicker/period-picker.tsx +16 -0
- package/src/components/WheelPicker/period-web.tsx +37 -0
- package/src/components/YearSelector.tsx +1 -1
- package/src/enums.ts +4 -3
- package/src/types.ts +5 -0
- package/src/utils.ts +3 -3
- /package/src/{CalendarContext.tsx → CalendarContext.ts} +0 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useRef, useState, memo } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
NativeSyntheticEvent,
|
|
4
|
+
NativeScrollEvent,
|
|
5
|
+
Animated,
|
|
6
|
+
ViewStyle,
|
|
7
|
+
View,
|
|
8
|
+
ViewProps,
|
|
9
|
+
FlatListProps,
|
|
10
|
+
FlatList,
|
|
11
|
+
Platform,
|
|
12
|
+
StyleSheet,
|
|
13
|
+
} from 'react-native';
|
|
14
|
+
import WheelPickerItem from './wheel-picker-item';
|
|
15
|
+
import { PickerOption } from '../../../types';
|
|
16
|
+
|
|
17
|
+
interface Props {
|
|
18
|
+
value: number | string;
|
|
19
|
+
options: PickerOption[];
|
|
20
|
+
onChange: (index: number | string) => void;
|
|
21
|
+
itemHeight?: number;
|
|
22
|
+
containerStyle?: ViewStyle;
|
|
23
|
+
containerProps?: Omit<ViewProps, 'style'>;
|
|
24
|
+
scaleFunction?: (x: number) => number;
|
|
25
|
+
rotationFunction?: (x: number) => number;
|
|
26
|
+
opacityFunction?: (x: number) => number;
|
|
27
|
+
visibleRest?: number;
|
|
28
|
+
decelerationRate?: 'normal' | 'fast' | number;
|
|
29
|
+
flatListProps?: Omit<FlatListProps<string | null>, 'data' | 'renderItem'>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const WheelPicker: React.FC<Props> = ({
|
|
33
|
+
value,
|
|
34
|
+
options,
|
|
35
|
+
onChange,
|
|
36
|
+
itemHeight = 40,
|
|
37
|
+
scaleFunction = (x: number) => 1.0 ** x,
|
|
38
|
+
rotationFunction = (x: number) => 1 - Math.pow(1 / 2, x),
|
|
39
|
+
opacityFunction = (x: number) => Math.pow(1 / 3, x),
|
|
40
|
+
visibleRest = 2,
|
|
41
|
+
decelerationRate = 'normal',
|
|
42
|
+
containerProps = {},
|
|
43
|
+
flatListProps = {},
|
|
44
|
+
}) => {
|
|
45
|
+
const momentumStarted = useRef(false);
|
|
46
|
+
const selectedIndex = options.findIndex((item) => item.value === value);
|
|
47
|
+
|
|
48
|
+
const flatListRef = useRef<FlatList>(null);
|
|
49
|
+
const [scrollY] = useState(new Animated.Value(selectedIndex * itemHeight));
|
|
50
|
+
|
|
51
|
+
const containerHeight = (1 + visibleRest * 2) * itemHeight;
|
|
52
|
+
const paddedOptions = useMemo(() => {
|
|
53
|
+
const array: (PickerOption | null)[] = [...options];
|
|
54
|
+
for (let i = 0; i < visibleRest; i++) {
|
|
55
|
+
array.unshift(null);
|
|
56
|
+
array.push(null);
|
|
57
|
+
}
|
|
58
|
+
return array;
|
|
59
|
+
}, [options, visibleRest]);
|
|
60
|
+
|
|
61
|
+
const offsets = useMemo(
|
|
62
|
+
() => [...Array(paddedOptions.length)].map((_, i) => i * itemHeight),
|
|
63
|
+
[paddedOptions, itemHeight]
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const currentScrollIndex = useMemo(
|
|
67
|
+
() => Animated.add(Animated.divide(scrollY, itemHeight), visibleRest),
|
|
68
|
+
[visibleRest, scrollY, itemHeight]
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const handleScrollEnd = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
72
|
+
const offsetY = Math.min(
|
|
73
|
+
itemHeight * (options.length - 1),
|
|
74
|
+
Math.max(event.nativeEvent.contentOffset.y, 0)
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
let index = Math.floor(offsetY / itemHeight);
|
|
78
|
+
const remainder = offsetY % itemHeight;
|
|
79
|
+
if (remainder > itemHeight / 2) {
|
|
80
|
+
index++;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (index !== selectedIndex) {
|
|
84
|
+
onChange(options[index]?.value || 0);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const handleMomentumScrollBegin = () => {
|
|
89
|
+
momentumStarted.current = true;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const handleMomentumScrollEnd = (
|
|
93
|
+
event: NativeSyntheticEvent<NativeScrollEvent>
|
|
94
|
+
) => {
|
|
95
|
+
momentumStarted.current = false;
|
|
96
|
+
handleScrollEnd(event);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const handleScrollEndDrag = (
|
|
100
|
+
event: NativeSyntheticEvent<NativeScrollEvent>
|
|
101
|
+
) => {
|
|
102
|
+
// Capture the offset value immediately
|
|
103
|
+
const offsetY = event.nativeEvent.contentOffset?.y;
|
|
104
|
+
|
|
105
|
+
// We'll start a short timer to see if momentum scroll begins
|
|
106
|
+
setTimeout(() => {
|
|
107
|
+
// If momentum scroll hasn't started within the timeout,
|
|
108
|
+
// then it was a slow scroll that won't trigger momentum
|
|
109
|
+
if (!momentumStarted.current && offsetY !== undefined) {
|
|
110
|
+
// Create a synthetic event with just the data we need
|
|
111
|
+
const syntheticEvent = {
|
|
112
|
+
nativeEvent: {
|
|
113
|
+
contentOffset: { y: offsetY },
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
handleScrollEnd(syntheticEvent as any);
|
|
117
|
+
}
|
|
118
|
+
}, 50);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
if (selectedIndex < 0 || selectedIndex >= options.length) {
|
|
123
|
+
throw new Error(
|
|
124
|
+
`Selected index ${selectedIndex} is out of bounds [0, ${
|
|
125
|
+
options.length - 1
|
|
126
|
+
}]`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}, [selectedIndex, options]);
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* If selectedIndex is changed from outside (not via onChange) we need to scroll to the specified index.
|
|
133
|
+
* This ensures that what the user sees as selected in the picker always corresponds to the value state.
|
|
134
|
+
*/
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
flatListRef.current?.scrollToIndex({
|
|
137
|
+
index: selectedIndex,
|
|
138
|
+
animated: Platform.OS === 'ios',
|
|
139
|
+
});
|
|
140
|
+
}, [selectedIndex, itemHeight]);
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<View
|
|
144
|
+
style={[styles.container, { height: containerHeight }]}
|
|
145
|
+
{...containerProps}
|
|
146
|
+
>
|
|
147
|
+
<View
|
|
148
|
+
style={[
|
|
149
|
+
styles.selectedIndicator,
|
|
150
|
+
{
|
|
151
|
+
transform: [{ translateY: -itemHeight / 2 }],
|
|
152
|
+
height: itemHeight,
|
|
153
|
+
},
|
|
154
|
+
]}
|
|
155
|
+
/>
|
|
156
|
+
<Animated.FlatList
|
|
157
|
+
{...flatListProps}
|
|
158
|
+
ref={flatListRef}
|
|
159
|
+
nestedScrollEnabled
|
|
160
|
+
style={styles.scrollView}
|
|
161
|
+
showsVerticalScrollIndicator={false}
|
|
162
|
+
onScroll={Animated.event(
|
|
163
|
+
[{ nativeEvent: { contentOffset: { y: scrollY } } }],
|
|
164
|
+
{ useNativeDriver: true }
|
|
165
|
+
)}
|
|
166
|
+
onScrollEndDrag={handleScrollEndDrag}
|
|
167
|
+
onMomentumScrollBegin={handleMomentumScrollBegin}
|
|
168
|
+
onMomentumScrollEnd={handleMomentumScrollEnd}
|
|
169
|
+
snapToOffsets={offsets}
|
|
170
|
+
decelerationRate={decelerationRate}
|
|
171
|
+
initialScrollIndex={selectedIndex}
|
|
172
|
+
getItemLayout={(_, index) => ({
|
|
173
|
+
length: itemHeight,
|
|
174
|
+
offset: itemHeight * index,
|
|
175
|
+
index,
|
|
176
|
+
})}
|
|
177
|
+
data={paddedOptions}
|
|
178
|
+
keyExtractor={(item, index) =>
|
|
179
|
+
item ? `${item.value}-${item.text}-${index}` : `null-${index}`
|
|
180
|
+
}
|
|
181
|
+
renderItem={({ item: option, index }) => (
|
|
182
|
+
<WheelPickerItem
|
|
183
|
+
key={`option-${index}`}
|
|
184
|
+
index={index}
|
|
185
|
+
option={option}
|
|
186
|
+
height={itemHeight}
|
|
187
|
+
currentScrollIndex={currentScrollIndex}
|
|
188
|
+
scaleFunction={scaleFunction}
|
|
189
|
+
rotationFunction={rotationFunction}
|
|
190
|
+
opacityFunction={opacityFunction}
|
|
191
|
+
visibleRest={visibleRest}
|
|
192
|
+
/>
|
|
193
|
+
)}
|
|
194
|
+
/>
|
|
195
|
+
</View>
|
|
196
|
+
);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const styles = StyleSheet.create({
|
|
200
|
+
container: {
|
|
201
|
+
position: 'relative',
|
|
202
|
+
},
|
|
203
|
+
selectedIndicator: {
|
|
204
|
+
position: 'absolute',
|
|
205
|
+
width: '100%',
|
|
206
|
+
top: '50%',
|
|
207
|
+
},
|
|
208
|
+
scrollView: {
|
|
209
|
+
overflow: 'hidden',
|
|
210
|
+
flex: 1,
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
export default memo(WheelPicker);
|
|
@@ -5,32 +5,37 @@ import {
|
|
|
5
5
|
StyleSheet,
|
|
6
6
|
View,
|
|
7
7
|
Platform,
|
|
8
|
+
Text,
|
|
8
9
|
} from 'react-native';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { sin } from './animated-math';
|
|
11
|
+
import { CONTAINER_HEIGHT } from '../../enums';
|
|
12
|
+
import { PickerOption } from '../../types';
|
|
13
|
+
import { isEqual } from 'lodash';
|
|
12
14
|
|
|
13
15
|
interface WheelProps {
|
|
14
|
-
value: number;
|
|
15
|
-
setValue?: (value:
|
|
16
|
-
items:
|
|
16
|
+
value: number | string;
|
|
17
|
+
setValue?: (value: any) => void;
|
|
18
|
+
items: PickerOption[];
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
const
|
|
20
|
-
const { theme } = useCalendarContext();
|
|
21
|
+
const ITEM_HEIGHT = 44;
|
|
21
22
|
|
|
23
|
+
const WheelWeb: React.FC<WheelProps> = ({
|
|
24
|
+
value,
|
|
25
|
+
setValue = () => {},
|
|
26
|
+
items,
|
|
27
|
+
}) => {
|
|
22
28
|
const displayCount = 5;
|
|
23
29
|
const translateY = useRef(new Animated.Value(0)).current;
|
|
24
30
|
const renderCount =
|
|
25
31
|
displayCount * 2 < items.length ? displayCount * 8 : displayCount * 2 - 1;
|
|
26
32
|
const circular = items.length >= displayCount;
|
|
27
|
-
const height =
|
|
33
|
+
const height = 140;
|
|
28
34
|
const radius = height / 2;
|
|
29
35
|
|
|
30
|
-
const valueIndex = useMemo(
|
|
31
|
-
() =>
|
|
32
|
-
|
|
33
|
-
);
|
|
36
|
+
const valueIndex = useMemo(() => {
|
|
37
|
+
return items.findIndex((item) => item.value === value) || 0;
|
|
38
|
+
}, [items, value]);
|
|
34
39
|
|
|
35
40
|
const panResponder = useMemo(() => {
|
|
36
41
|
return PanResponder.create({
|
|
@@ -54,11 +59,12 @@ const WheelWeb = ({ value, setValue = () => {}, items }: WheelProps) => {
|
|
|
54
59
|
else if (newValueIndex >= items.length)
|
|
55
60
|
newValueIndex = items.length - 1;
|
|
56
61
|
|
|
57
|
-
const newValue = items[newValueIndex]
|
|
58
|
-
if (newValue ===
|
|
62
|
+
const newValue = items[newValueIndex];
|
|
63
|
+
if (newValue?.value === value) {
|
|
59
64
|
translateY.setOffset(0);
|
|
60
65
|
translateY.setValue(0);
|
|
61
|
-
} else setValue(
|
|
66
|
+
} else if (newValue?.value) setValue(newValue.value);
|
|
67
|
+
else if (items[0]?.value) setValue(items[0].value);
|
|
62
68
|
},
|
|
63
69
|
});
|
|
64
70
|
}, [
|
|
@@ -77,19 +83,21 @@ const WheelWeb = ({ value, setValue = () => {}, items }: WheelProps) => {
|
|
|
77
83
|
|
|
78
84
|
return Array.from({ length: renderCount }, (_, index) => {
|
|
79
85
|
let targetIndex = valueIndex + index - centerIndex;
|
|
80
|
-
if (
|
|
81
|
-
|
|
86
|
+
if (circular)
|
|
87
|
+
targetIndex =
|
|
88
|
+
((targetIndex % items.length) + items.length) % items.length;
|
|
89
|
+
else targetIndex = Math.max(0, Math.min(targetIndex, items.length - 1));
|
|
82
90
|
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
return items[targetIndex] || 0;
|
|
91
|
+
return items[targetIndex] || items[0];
|
|
86
92
|
});
|
|
87
93
|
}, [renderCount, valueIndex, items, circular]);
|
|
88
94
|
|
|
89
95
|
const animatedAngles = useMemo(() => {
|
|
90
96
|
//translateY.setValue(0);
|
|
91
97
|
translateY.setOffset(0);
|
|
92
|
-
const currentIndex = displayValues.
|
|
98
|
+
const currentIndex = displayValues.findIndex(
|
|
99
|
+
(item) => item?.value === value
|
|
100
|
+
);
|
|
93
101
|
return displayValues && displayValues.length > 0
|
|
94
102
|
? displayValues.map((_, index) =>
|
|
95
103
|
translateY
|
|
@@ -112,54 +120,57 @@ const WheelWeb = ({ value, setValue = () => {}, items }: WheelProps) => {
|
|
|
112
120
|
}, [displayValues, radius, value, displayCount, translateY]);
|
|
113
121
|
|
|
114
122
|
return (
|
|
115
|
-
<View style={[
|
|
123
|
+
<View style={[defaultStyles.container]} {...panResponder.panHandlers}>
|
|
124
|
+
<View
|
|
125
|
+
style={[
|
|
126
|
+
defaultStyles.selectedIndicator,
|
|
127
|
+
{
|
|
128
|
+
transform: [{ translateY: -ITEM_HEIGHT / 2 }],
|
|
129
|
+
height: ITEM_HEIGHT,
|
|
130
|
+
},
|
|
131
|
+
]}
|
|
132
|
+
/>
|
|
116
133
|
{displayValues?.map((displayValue, index) => {
|
|
117
134
|
const animatedAngle = animatedAngles[index];
|
|
118
135
|
return (
|
|
119
|
-
<Animated.
|
|
120
|
-
key={`${displayValue}-${index}`}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
},
|
|
142
|
-
]
|
|
143
|
-
: [],
|
|
144
|
-
opacity: displayValue !== ('0' + value).slice(-2) ? 0.3 : 1,
|
|
145
|
-
},
|
|
146
|
-
]}
|
|
136
|
+
<Animated.View
|
|
137
|
+
key={`${displayValue?.text}-${index}`}
|
|
138
|
+
// eslint-disable-next-line react-native/no-inline-styles
|
|
139
|
+
style={{
|
|
140
|
+
position: 'absolute',
|
|
141
|
+
height: ITEM_HEIGHT - 10,
|
|
142
|
+
transform: animatedAngle
|
|
143
|
+
? [
|
|
144
|
+
{
|
|
145
|
+
translateY: Animated.multiply(radius, sin(animatedAngle)),
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
rotateX: animatedAngle.interpolate({
|
|
149
|
+
inputRange: [-Math.PI / 2, Math.PI / 2],
|
|
150
|
+
outputRange: ['-89deg', '89deg'],
|
|
151
|
+
extrapolate: 'clamp',
|
|
152
|
+
}),
|
|
153
|
+
},
|
|
154
|
+
]
|
|
155
|
+
: [],
|
|
156
|
+
opacity: displayValue?.value !== value ? 0.3 : 1,
|
|
157
|
+
}}
|
|
147
158
|
>
|
|
148
|
-
{displayValue}
|
|
149
|
-
</Animated.
|
|
159
|
+
<Text>{displayValue?.text}</Text>
|
|
160
|
+
</Animated.View>
|
|
150
161
|
);
|
|
151
162
|
})}
|
|
152
163
|
</View>
|
|
153
164
|
);
|
|
154
165
|
};
|
|
155
166
|
|
|
156
|
-
const
|
|
167
|
+
const defaultStyles = StyleSheet.create({
|
|
157
168
|
container: {
|
|
158
169
|
minWidth: 30,
|
|
159
170
|
overflow: 'hidden',
|
|
160
171
|
alignItems: 'center',
|
|
161
172
|
justifyContent: 'center',
|
|
162
|
-
height:
|
|
173
|
+
height: CONTAINER_HEIGHT / 2,
|
|
163
174
|
...Platform.select({
|
|
164
175
|
web: {
|
|
165
176
|
cursor: 'pointer',
|
|
@@ -171,15 +182,23 @@ const styles = StyleSheet.create({
|
|
|
171
182
|
justifyContent: 'space-between',
|
|
172
183
|
alignItems: 'center',
|
|
173
184
|
},
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
185
|
+
selectedIndicator: {
|
|
186
|
+
position: 'absolute',
|
|
187
|
+
width: '100%',
|
|
188
|
+
top: '50%',
|
|
177
189
|
},
|
|
178
190
|
});
|
|
179
191
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
192
|
+
const customComparator = (
|
|
193
|
+
prev: Readonly<WheelProps>,
|
|
194
|
+
next: Readonly<WheelProps>
|
|
195
|
+
) => {
|
|
196
|
+
const areEqual =
|
|
197
|
+
prev.value === next.value &&
|
|
198
|
+
prev.setValue === next.setValue &&
|
|
199
|
+
isEqual(prev.items, next.items);
|
|
200
|
+
|
|
201
|
+
return areEqual;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
export default memo(WheelWeb, customComparator);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Animated } from 'react-native';
|
|
2
|
+
|
|
3
|
+
const FACTORIAL_3 = 3 * 2;
|
|
4
|
+
const FACTORIAL_5 = 5 * 4 * FACTORIAL_3;
|
|
5
|
+
const FACTORIAL_7 = 7 * 6 * FACTORIAL_5;
|
|
6
|
+
|
|
7
|
+
function sin(animated: Animated.Animated) {
|
|
8
|
+
const normalized = normalize(animated);
|
|
9
|
+
const square = Animated.multiply(normalized, normalized);
|
|
10
|
+
const pow3 = Animated.multiply(normalized, square);
|
|
11
|
+
const pow5 = Animated.multiply(pow3, square);
|
|
12
|
+
const pow7 = Animated.multiply(pow5, square);
|
|
13
|
+
|
|
14
|
+
return Animated.add(
|
|
15
|
+
Animated.add(normalized, Animated.multiply(pow3, -1 / FACTORIAL_3)),
|
|
16
|
+
Animated.add(
|
|
17
|
+
Animated.multiply(pow5, 1 / FACTORIAL_5),
|
|
18
|
+
Animated.multiply(pow7, -1 / FACTORIAL_7)
|
|
19
|
+
)
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function normalize(animated: Animated.Animated): Animated.Animated {
|
|
24
|
+
return Animated.add(
|
|
25
|
+
Animated.modulo(Animated.add(animated, Math.PI), Math.PI * 2),
|
|
26
|
+
-Math.PI
|
|
27
|
+
).interpolate({
|
|
28
|
+
inputRange: [-Math.PI, -Math.PI / 2, Math.PI / 2, Math.PI],
|
|
29
|
+
outputRange: [0, -Math.PI / 2, Math.PI / 2, 0],
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { sin, normalize };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import WheelPicker from './WheelNativePicker';
|
|
3
|
+
import { PickerOption } from '../../types';
|
|
4
|
+
|
|
5
|
+
interface PeriodProps {
|
|
6
|
+
value: string;
|
|
7
|
+
setValue?: (value: any) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const options: PickerOption[] = [
|
|
11
|
+
{ value: 'AM', text: 'AM' },
|
|
12
|
+
{ value: 'PM', text: 'PM' },
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const PeriodNative: React.FC<PeriodProps> = ({
|
|
16
|
+
value,
|
|
17
|
+
setValue = () => {},
|
|
18
|
+
}) => {
|
|
19
|
+
return (
|
|
20
|
+
<WheelPicker
|
|
21
|
+
value={value}
|
|
22
|
+
options={options}
|
|
23
|
+
onChange={setValue}
|
|
24
|
+
itemHeight={44}
|
|
25
|
+
decelerationRate="fast"
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const customComparator = (
|
|
31
|
+
prev: Readonly<PeriodProps>,
|
|
32
|
+
next: Readonly<PeriodProps>
|
|
33
|
+
) => {
|
|
34
|
+
const areEqual = prev.value === next.value && prev.setValue === next.setValue;
|
|
35
|
+
|
|
36
|
+
return areEqual;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default memo(PeriodNative, customComparator);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import { Platform } from 'react-native';
|
|
3
|
+
import PeriodNative from './period-native';
|
|
4
|
+
import PeriodWeb from './period-web';
|
|
5
|
+
|
|
6
|
+
type PeriodProps = {
|
|
7
|
+
value: string;
|
|
8
|
+
setValue?: (value: any) => void;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const PeriodPicker: React.FC<PeriodProps> = (props) => {
|
|
12
|
+
const Component = Platform.OS === 'web' ? PeriodWeb : PeriodNative;
|
|
13
|
+
return <Component {...props} />;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default memo(PeriodPicker);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
interface PeriodProps {
|
|
5
|
+
value: string;
|
|
6
|
+
setValue?: (value: any) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const PeriodWeb: React.FC<PeriodProps> = ({ value, setValue = () => {} }) => {
|
|
10
|
+
return (
|
|
11
|
+
<Pressable onPress={() => setValue(value == 'AM' ? 'PM' : 'AM')}>
|
|
12
|
+
<View style={[defaultStyles.period]}>
|
|
13
|
+
<Text>{value}</Text>
|
|
14
|
+
</View>
|
|
15
|
+
</Pressable>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const defaultStyles = StyleSheet.create({
|
|
20
|
+
period: {
|
|
21
|
+
width: 65,
|
|
22
|
+
height: 44,
|
|
23
|
+
alignItems: 'center',
|
|
24
|
+
justifyContent: 'center',
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const customComparator = (
|
|
29
|
+
prev: Readonly<PeriodProps>,
|
|
30
|
+
next: Readonly<PeriodProps>
|
|
31
|
+
) => {
|
|
32
|
+
const areEqual = prev.value === next.value && prev.setValue === next.setValue;
|
|
33
|
+
|
|
34
|
+
return areEqual;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default memo(PeriodWeb, customComparator);
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import { useCalendarContext } from '../CalendarContext';
|
|
11
11
|
import { getDateYear, getYearRange } from '../utils';
|
|
12
12
|
|
|
13
|
-
const YearSelector = () => {
|
|
13
|
+
const YearSelector: React.FC = () => {
|
|
14
14
|
const { currentDate, currentYear, onSelectYear, theme } =
|
|
15
15
|
useCalendarContext();
|
|
16
16
|
const selectedYear = getDateYear(currentDate);
|
package/src/enums.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* @Author: limit
|
|
3
3
|
* @Date: 2024-07-17 05:09:59
|
|
4
|
-
* @LastEditTime:
|
|
4
|
+
* @LastEditTime: 2025-08-07 16:31:49
|
|
5
5
|
* @LastEditors: limit
|
|
6
|
-
* @FilePath: /
|
|
6
|
+
* @FilePath: /react-native-date-picker/src/enums.ts
|
|
7
7
|
* @Description: 由limit创建!
|
|
8
8
|
*/
|
|
9
9
|
export type CalendarViews = 'day' | 'month' | 'year' | 'time';
|
|
@@ -17,4 +17,5 @@ export enum CalendarActionKind {
|
|
|
17
17
|
CHANGE_SELECTED_MULTIPLE = 'CHANGE_SELECTED_MULTIPLE',
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export const
|
|
20
|
+
export const CONTAINER_HEIGHT = 300;
|
|
21
|
+
export const WEEKDAYS_HEIGHT = 25;
|
package/src/types.ts
CHANGED
package/src/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import dayjs from 'dayjs';
|
|
2
|
-
import type { DateType, IDayObject } from './types';
|
|
2
|
+
import type { DateType, IDayObject, PickerOption } from './types';
|
|
3
3
|
|
|
4
4
|
export const CALENDAR_FORMAT = 'YYYY-MM-DD HH:mm:ss';
|
|
5
5
|
export const DATE_FORMAT = 'YYYY-MM-DD';
|
|
@@ -105,7 +105,7 @@ export function getDaysNumInMonth(
|
|
|
105
105
|
month: number,
|
|
106
106
|
minDate: DateType,
|
|
107
107
|
maxDate: DateType
|
|
108
|
-
):
|
|
108
|
+
): Array<PickerOption> {
|
|
109
109
|
const formattedMonth = String(month).padStart(2, '0');
|
|
110
110
|
const date = dayjs(`${year}-${formattedMonth}-01`);
|
|
111
111
|
const daysInMonth = date.daysInMonth();
|
|
@@ -121,7 +121,7 @@ export function getDaysNumInMonth(
|
|
|
121
121
|
(currentDate.isAfter(minDay) || currentDate.isSame(minDay, 'day')) &&
|
|
122
122
|
(currentDate.isBefore(maxDay) || currentDate.isSame(maxDay, 'day'))
|
|
123
123
|
)
|
|
124
|
-
daysArray.push(String(day).padStart(2, '0'));
|
|
124
|
+
daysArray.push({ value: day, text: String(day).padStart(2, '0') });
|
|
125
125
|
}
|
|
126
126
|
return daysArray;
|
|
127
127
|
}
|
|
File without changes
|