react-native-dates-picker 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/lib/commonjs/DateTimePicker.js +144 -85
  2. package/lib/commonjs/DateTimePicker.js.map +1 -1
  3. package/lib/commonjs/components/Calendar.js +3 -5
  4. package/lib/commonjs/components/Calendar.js.map +1 -1
  5. package/lib/commonjs/components/DatePicker.js +16 -83
  6. package/lib/commonjs/components/DatePicker.js.map +1 -1
  7. package/lib/commonjs/components/Day.js +3 -8
  8. package/lib/commonjs/components/Day.js.map +1 -1
  9. package/lib/commonjs/components/TimeSelector.js +3 -3
  10. package/lib/commonjs/components/TimeSelector.js.map +1 -1
  11. package/lib/commonjs/components/WheelPicker/WheelNative.js +2 -2
  12. package/lib/commonjs/components/WheelPicker/WheelNative.js.map +1 -1
  13. package/lib/commonjs/components/WheelPicker/WheelNativePicker/wheel-picker-item.js +56 -72
  14. package/lib/commonjs/components/WheelPicker/WheelNativePicker/wheel-picker-item.js.map +1 -1
  15. package/lib/commonjs/components/WheelPicker/WheelNativePicker/wheel-picker.js +27 -48
  16. package/lib/commonjs/components/WheelPicker/WheelNativePicker/wheel-picker.js.map +1 -1
  17. package/lib/commonjs/components/WheelPicker/WheelWeb.js +5 -7
  18. package/lib/commonjs/components/WheelPicker/WheelWeb.js.map +1 -1
  19. package/lib/commonjs/components/WheelSelector.js +129 -0
  20. package/lib/commonjs/components/WheelSelector.js.map +1 -0
  21. package/lib/commonjs/utils.js +68 -0
  22. package/lib/commonjs/utils.js.map +1 -1
  23. package/lib/module/DateTimePicker.js +146 -87
  24. package/lib/module/DateTimePicker.js.map +1 -1
  25. package/lib/module/components/Calendar.js +3 -5
  26. package/lib/module/components/Calendar.js.map +1 -1
  27. package/lib/module/components/DatePicker.js +16 -81
  28. package/lib/module/components/DatePicker.js.map +1 -1
  29. package/lib/module/components/Day.js +3 -8
  30. package/lib/module/components/Day.js.map +1 -1
  31. package/lib/module/components/TimeSelector.js +3 -3
  32. package/lib/module/components/TimeSelector.js.map +1 -1
  33. package/lib/module/components/WheelPicker/WheelNative.js +2 -2
  34. package/lib/module/components/WheelPicker/WheelNative.js.map +1 -1
  35. package/lib/module/components/WheelPicker/WheelNativePicker/wheel-picker-item.js +57 -73
  36. package/lib/module/components/WheelPicker/WheelNativePicker/wheel-picker-item.js.map +1 -1
  37. package/lib/module/components/WheelPicker/WheelNativePicker/wheel-picker.js +27 -48
  38. package/lib/module/components/WheelPicker/WheelNativePicker/wheel-picker.js.map +1 -1
  39. package/lib/module/components/WheelPicker/WheelWeb.js +5 -7
  40. package/lib/module/components/WheelPicker/WheelWeb.js.map +1 -1
  41. package/lib/module/components/WheelSelector.js +120 -0
  42. package/lib/module/components/WheelSelector.js.map +1 -0
  43. package/lib/module/utils.js +65 -0
  44. package/lib/module/utils.js.map +1 -1
  45. package/lib/typescript/DateTimePicker.d.ts +2 -2
  46. package/lib/typescript/DateTimePicker.d.ts.map +1 -1
  47. package/lib/typescript/components/Calendar.d.ts.map +1 -1
  48. package/lib/typescript/components/DatePicker.d.ts +6 -1
  49. package/lib/typescript/components/DatePicker.d.ts.map +1 -1
  50. package/lib/typescript/components/Day.d.ts.map +1 -1
  51. package/lib/typescript/components/WheelPicker/Wheel.d.ts +1 -1
  52. package/lib/typescript/components/WheelPicker/WheelNative.d.ts +1 -1
  53. package/lib/typescript/components/WheelPicker/WheelNativePicker/wheel-picker-item.d.ts.map +1 -1
  54. package/lib/typescript/components/WheelPicker/WheelNativePicker/wheel-picker.d.ts +1 -2
  55. package/lib/typescript/components/WheelPicker/WheelNativePicker/wheel-picker.d.ts.map +1 -1
  56. package/lib/typescript/components/WheelPicker/WheelWeb.d.ts +1 -1
  57. package/lib/typescript/components/WheelPicker/WheelWeb.d.ts.map +1 -1
  58. package/lib/typescript/components/WheelSelector.d.ts +8 -0
  59. package/lib/typescript/components/WheelSelector.d.ts.map +1 -0
  60. package/lib/typescript/types.d.ts +1 -1
  61. package/lib/typescript/types.d.ts.map +1 -1
  62. package/lib/typescript/utils.d.ts +9 -0
  63. package/lib/typescript/utils.d.ts.map +1 -1
  64. package/package.json +2 -3
  65. package/src/DateTimePicker.tsx +226 -108
  66. package/src/components/Calendar.tsx +3 -11
  67. package/src/components/DatePicker.tsx +17 -138
  68. package/src/components/Day.tsx +1 -4
  69. package/src/components/TimeSelector.tsx +3 -3
  70. package/src/components/WheelPicker/Wheel.tsx +1 -1
  71. package/src/components/WheelPicker/WheelNative.tsx +3 -3
  72. package/src/components/WheelPicker/WheelNativePicker/wheel-picker-item.tsx +65 -74
  73. package/src/components/WheelPicker/WheelNativePicker/wheel-picker.tsx +21 -48
  74. package/src/components/WheelPicker/WheelWeb.tsx +6 -7
  75. package/src/components/WheelSelector.tsx +170 -0
  76. package/src/types.ts +1 -1
  77. package/src/utils.ts +77 -0
  78. package/lib/commonjs/components/WheelPicker/AnimatedMath.js +0 -26
  79. package/lib/commonjs/components/WheelPicker/AnimatedMath.js.map +0 -1
  80. package/lib/module/components/WheelPicker/AnimatedMath.js +0 -20
  81. package/lib/module/components/WheelPicker/AnimatedMath.js.map +0 -1
  82. package/lib/typescript/components/WheelPicker/AnimatedMath.d.ts +0 -5
  83. package/lib/typescript/components/WheelPicker/AnimatedMath.d.ts.map +0 -1
  84. package/src/components/WheelPicker/AnimatedMath.tsx +0 -33
@@ -1,9 +1,8 @@
1
1
  import React, { memo, useCallback } from 'react';
2
2
  import { View, Text, Pressable, StyleSheet } from 'react-native';
3
- import { isEqual } from 'lodash';
4
3
  import { CalendarThemeProps, IDayObject } from '../types';
5
4
  import { CONTAINER_HEIGHT } from '../enums';
6
- import { addColorAlpha } from '../utils';
5
+ import { addColorAlpha, isEqual } from '../utils';
7
6
 
8
7
  export const daySize = 46;
9
8
 
@@ -97,7 +96,6 @@ const Day: React.FC<Props> = ({
97
96
  <View
98
97
  style={[
99
98
  style.rangeRoot,
100
- // eslint-disable-next-line react-native/no-inline-styles
101
99
  {
102
100
  left: '50%',
103
101
  backgroundColor: rangeRootBackground,
@@ -110,7 +108,6 @@ const Day: React.FC<Props> = ({
110
108
  <View
111
109
  style={[
112
110
  style.rangeRoot,
113
- // eslint-disable-next-line react-native/no-inline-styles
114
111
  {
115
112
  right: '50%',
116
113
  backgroundColor: rangeRootBackground,
@@ -35,7 +35,7 @@ const TimeSelector: React.FC = () => {
35
35
  <Wheel
36
36
  value={hour}
37
37
  items={hours}
38
- setValue={(value) => handleChange(value, 'hour')}
38
+ onChange={(value) => handleChange(value, 'hour')}
39
39
  />
40
40
  </View>
41
41
  <Text
@@ -50,7 +50,7 @@ const TimeSelector: React.FC = () => {
50
50
  <Wheel
51
51
  value={minute}
52
52
  items={minutes}
53
- setValue={(value) => handleChange(value, 'minute')}
53
+ onChange={(value) => handleChange(value, 'minute')}
54
54
  />
55
55
  </View>
56
56
  <Text
@@ -65,7 +65,7 @@ const TimeSelector: React.FC = () => {
65
65
  <Wheel
66
66
  value={second}
67
67
  items={seconds}
68
- setValue={(value) => handleChange(value, 'second')}
68
+ onChange={(value) => handleChange(value, 'second')}
69
69
  />
70
70
  </View>
71
71
  </View>
@@ -6,7 +6,7 @@ import { PickerOption } from '../../types';
6
6
 
7
7
  interface WheelProps {
8
8
  value: number;
9
- setValue?: (value: number) => void;
9
+ onChange?: (value: number) => void;
10
10
  items: Array<PickerOption>;
11
11
  }
12
12
 
@@ -4,20 +4,20 @@ import { PickerOption } from '../../types';
4
4
 
5
5
  interface WheelProps {
6
6
  value: number | string;
7
- setValue?: (value: any) => void;
7
+ onChange?: (value: any) => void;
8
8
  items: PickerOption[];
9
9
  }
10
10
 
11
11
  const WheelNative: React.FC<WheelProps> = ({
12
12
  value,
13
- setValue = () => {},
13
+ onChange = () => {},
14
14
  items,
15
15
  }) => {
16
16
  return (
17
17
  <WheelPicker
18
18
  value={value}
19
19
  options={items}
20
- onChange={setValue}
20
+ onChange={onChange}
21
21
  itemHeight={44}
22
22
  decelerationRate="fast"
23
23
  />
@@ -1,4 +1,4 @@
1
- import React, { memo } from 'react';
1
+ import React, { memo, useMemo } from 'react';
2
2
  import { Animated, Text, StyleSheet } from 'react-native';
3
3
  import { useCalendarContext } from '../../../CalendarContext';
4
4
  import { PickerOption } from '../../../types';
@@ -25,90 +25,81 @@ const WheelPickerItem: React.FC<ItemProps> = ({
25
25
  scaleFunction,
26
26
  }) => {
27
27
  const { theme } = useCalendarContext();
28
- const relativeScrollIndex = Animated.subtract(index, currentScrollIndex);
28
+ const relativeScrollIndex = useMemo(
29
+ () => Animated.subtract(index, currentScrollIndex),
30
+ [index, currentScrollIndex]
31
+ );
29
32
 
30
- const translateY = relativeScrollIndex.interpolate({
31
- inputRange: (() => {
32
- const range = [0];
33
- for (let i = 1; i <= visibleRest + 1; i++) {
34
- range.unshift(-i);
35
- range.push(i);
36
- }
37
- return range;
38
- })(),
39
- outputRange: (() => {
40
- const range = [0];
41
- for (let i = 1; i <= visibleRest + 1; i++) {
42
- let y =
43
- (height / 2) * (1 - Math.sin(Math.PI / 2 - rotationFunction(i)));
44
- for (let j = 1; j < i; j++) {
45
- y += height * (1 - Math.sin(Math.PI / 2 - rotationFunction(j)));
46
- }
47
- range.unshift(y);
48
- range.push(-y);
33
+ const interpolInputRange = useMemo(() => {
34
+ const range = [0];
35
+ for (let i = 1; i <= visibleRest + 1; i++) {
36
+ range.unshift(-i);
37
+ range.push(i);
38
+ }
39
+ return range;
40
+ }, [visibleRest]);
41
+
42
+ const translateYOutputRange = useMemo(() => {
43
+ const range = [0];
44
+ for (let i = 1; i <= visibleRest + 1; i++) {
45
+ let y = (height / 2) * (1 - Math.sin(Math.PI / 2 - rotationFunction(i)));
46
+ for (let j = 1; j < i; j++) {
47
+ y += height * (1 - Math.sin(Math.PI / 2 - rotationFunction(j)));
49
48
  }
50
- return range;
51
- })(),
49
+ range.unshift(y);
50
+ range.push(-y);
51
+ }
52
+ return range;
53
+ }, [height, visibleRest, rotationFunction]);
54
+
55
+ const opacityOutputRange = useMemo(() => {
56
+ const range = [1];
57
+ for (let x = 1; x <= visibleRest + 1; x++) {
58
+ const val = opacityFunction(x);
59
+ range.unshift(val);
60
+ range.push(val);
61
+ }
62
+ return range;
63
+ }, [visibleRest, opacityFunction]);
64
+
65
+ const scaleOutputRange = useMemo(() => {
66
+ const range = [1];
67
+ for (let x = 1; x <= visibleRest + 1; x++) {
68
+ const val = scaleFunction(x);
69
+ range.unshift(val);
70
+ range.push(val);
71
+ }
72
+ return range;
73
+ }, [visibleRest, scaleFunction]);
74
+
75
+ const rotateXOutputRange = useMemo(() => {
76
+ const range = ['0deg'];
77
+ for (let x = 1; x <= visibleRest + 1; x++) {
78
+ const deg = `${rotationFunction(x)}deg`;
79
+ range.unshift(deg);
80
+ range.push(deg);
81
+ }
82
+ return range;
83
+ }, [visibleRest, rotationFunction]);
84
+
85
+ const translateY = relativeScrollIndex.interpolate({
86
+ inputRange: interpolInputRange,
87
+ outputRange: translateYOutputRange,
52
88
  });
53
89
 
54
90
  const opacity = relativeScrollIndex.interpolate({
55
- inputRange: (() => {
56
- const range = [0];
57
- for (let i = 1; i <= visibleRest + 1; i++) {
58
- range.unshift(-i);
59
- range.push(i);
60
- }
61
- return range;
62
- })(),
63
- outputRange: (() => {
64
- const range = [1];
65
- for (let x = 1; x <= visibleRest + 1; x++) {
66
- const y = opacityFunction(x);
67
- range.unshift(y);
68
- range.push(y);
69
- }
70
- return range;
71
- })(),
91
+ inputRange: interpolInputRange,
92
+ outputRange: opacityOutputRange,
72
93
  });
73
94
 
74
95
  const scale = relativeScrollIndex.interpolate({
75
- inputRange: (() => {
76
- const range = [0];
77
- for (let i = 1; i <= visibleRest + 1; i++) {
78
- range.unshift(-i);
79
- range.push(i);
80
- }
81
- return range;
82
- })(),
83
- outputRange: (() => {
84
- const range = [1.0];
85
- for (let x = 1; x <= visibleRest + 1; x++) {
86
- const y = scaleFunction(x);
87
- range.unshift(y);
88
- range.push(y);
89
- }
90
- return range;
91
- })(),
96
+ inputRange: interpolInputRange,
97
+ outputRange: scaleOutputRange,
92
98
  });
93
99
 
94
100
  const rotateX = relativeScrollIndex.interpolate({
95
- inputRange: (() => {
96
- const range = [0];
97
- for (let i = 1; i <= visibleRest + 1; i++) {
98
- range.unshift(-i);
99
- range.push(i);
100
- }
101
- return range;
102
- })(),
103
- outputRange: (() => {
104
- const range = ['0deg'];
105
- for (let x = 1; x <= visibleRest + 1; x++) {
106
- const y = rotationFunction(x);
107
- range.unshift(`${y}deg`);
108
- range.push(`${y}deg`);
109
- }
110
- return range;
111
- })(),
101
+ inputRange: interpolInputRange,
102
+ outputRange: rotateXOutputRange,
112
103
  });
113
104
 
114
105
  return (
@@ -5,7 +5,6 @@ import {
5
5
  Animated,
6
6
  View,
7
7
  ViewProps,
8
- FlatListProps,
9
8
  FlatList,
10
9
  Platform,
11
10
  StyleSheet,
@@ -25,7 +24,6 @@ interface Props {
25
24
  opacityFunction?: (x: number) => number;
26
25
  visibleRest?: number;
27
26
  decelerationRate?: 'normal' | 'fast' | number;
28
- flatListProps?: Omit<FlatListProps<string | null>, 'data' | 'renderItem'>;
29
27
  }
30
28
 
31
29
  const WheelPicker: React.FC<Props> = ({
@@ -39,11 +37,10 @@ const WheelPicker: React.FC<Props> = ({
39
37
  visibleRest = 2,
40
38
  decelerationRate = 'normal',
41
39
  containerProps = {},
42
- flatListProps = {},
43
40
  }) => {
44
41
  const { theme } = useCalendarContext();
45
- const momentumStarted = useRef(false);
46
42
  const selectedIndex = options.findIndex((item) => item.value === value);
43
+ const timerRef = useRef<NodeJS.Timeout>();
47
44
 
48
45
  const flatListRef = useRef<FlatList>(null);
49
46
  const [scrollY] = useState(new Animated.Value(selectedIndex * itemHeight));
@@ -69,54 +66,35 @@ const WheelPicker: React.FC<Props> = ({
69
66
  );
70
67
 
71
68
  const handleScrollEnd = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
69
+ if (timerRef.current) clearTimeout(timerRef.current);
72
70
  const offsetY = Math.min(
73
71
  itemHeight * (options.length - 1),
74
72
  Math.max(event.nativeEvent.contentOffset.y, 0)
75
73
  );
76
-
77
74
  let index = Math.floor(offsetY / itemHeight);
78
75
  const remainder = offsetY % itemHeight;
79
76
  if (remainder > itemHeight / 2) {
80
77
  index++;
81
78
  }
82
-
79
+ const value = options[index]?.value || 0;
83
80
  if (index !== selectedIndex) {
84
- onChange(options[index]?.value || 0);
81
+ timerRef.current = setTimeout(() => {
82
+ onChange(value);
83
+ clearTimeout(timerRef.current!);
84
+ timerRef.current = undefined;
85
+ }, 50);
85
86
  }
86
87
  };
87
88
 
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
- };
89
+ const scrollEvent = useMemo(
90
+ () =>
91
+ Animated.event([{ nativeEvent: { contentOffset: { y: scrollY } } }], {
92
+ useNativeDriver: true,
93
+ listener: handleScrollEnd,
94
+ }),
95
+ // eslint-disable-next-line react-hooks/exhaustive-deps
96
+ []
97
+ );
120
98
 
121
99
  useEffect(() => {
122
100
  if (selectedIndex < 0 || selectedIndex >= options.length) {
@@ -159,19 +137,14 @@ const WheelPicker: React.FC<Props> = ({
159
137
  ]}
160
138
  />
161
139
  <Animated.FlatList
162
- {...flatListProps}
163
140
  ref={flatListRef}
164
141
  nestedScrollEnabled
165
142
  style={styles.scrollView}
166
143
  showsVerticalScrollIndicator={false}
167
- onScroll={Animated.event(
168
- [{ nativeEvent: { contentOffset: { y: scrollY } } }],
169
- { useNativeDriver: true }
170
- )}
171
- onScrollEndDrag={handleScrollEndDrag}
172
- onMomentumScrollBegin={handleMomentumScrollBegin}
173
- onMomentumScrollEnd={handleMomentumScrollEnd}
144
+ scrollEventThrottle={16}
145
+ onScroll={scrollEvent}
174
146
  snapToOffsets={offsets}
147
+ onMomentumScrollEnd={handleScrollEnd}
175
148
  decelerationRate={decelerationRate}
176
149
  initialScrollIndex={selectedIndex}
177
150
  getItemLayout={(_, index) => ({
@@ -181,7 +154,7 @@ const WheelPicker: React.FC<Props> = ({
181
154
  })}
182
155
  data={paddedOptions}
183
156
  keyExtractor={(item, index) =>
184
- item ? `${item.value}-${item.text}-${index}` : `null-${index}`
157
+ item ? `${item.value}-${item.text}-${index}` : `-${index}`
185
158
  }
186
159
  renderItem={({ item: option, index }) => (
187
160
  <WheelPickerItem
@@ -15,7 +15,7 @@ import { sin } from './animated-math';
15
15
 
16
16
  interface WheelProps {
17
17
  value: number | string;
18
- setValue?: (value: any) => void;
18
+ onChange?: (value: any) => void;
19
19
  items: PickerOption[];
20
20
  }
21
21
 
@@ -23,7 +23,7 @@ const ITEM_HEIGHT = 44;
23
23
 
24
24
  const WheelWeb: React.FC<WheelProps> = ({
25
25
  value,
26
- setValue = () => {},
26
+ onChange = () => {},
27
27
  items,
28
28
  }) => {
29
29
  const { theme } = useCalendarContext();
@@ -65,15 +65,15 @@ const WheelWeb: React.FC<WheelProps> = ({
65
65
  if (newValue?.value === value) {
66
66
  translateY.setOffset(0);
67
67
  translateY.setValue(0);
68
- } else if (newValue?.value) setValue(newValue.value);
69
- else if (items[0]?.value) setValue(items[0].value);
68
+ } else if (newValue?.value) onChange(newValue.value);
69
+ else if (items[0]?.value) onChange(items[0].value);
70
70
  },
71
71
  });
72
72
  }, [
73
73
  circular,
74
74
  displayCount,
75
75
  radius,
76
- setValue,
76
+ onChange,
77
77
  value,
78
78
  valueIndex,
79
79
  items,
@@ -141,7 +141,6 @@ const WheelWeb: React.FC<WheelProps> = ({
141
141
  return (
142
142
  <Animated.View
143
143
  key={`${displayValue?.text}-${index}`}
144
- // eslint-disable-next-line react-native/no-inline-styles
145
144
  style={{
146
145
  position: 'absolute',
147
146
  height: ITEM_HEIGHT - 10,
@@ -203,7 +202,7 @@ const customComparator = (
203
202
  ) => {
204
203
  const areEqual =
205
204
  prev.value === next.value &&
206
- prev.setValue === next.setValue &&
205
+ prev.onChange === next.onChange &&
207
206
  isEqual(prev.items, next.items);
208
207
 
209
208
  return areEqual;
@@ -0,0 +1,170 @@
1
+ import React, { useCallback, useEffect, useMemo, useRef } from 'react';
2
+ import { View, StyleSheet } from 'react-native';
3
+ import { useCalendarContext } from '../CalendarContext';
4
+ import {
5
+ getFormatted,
6
+ getParsedDate,
7
+ getDaysNumInMonth,
8
+ getTimeRange,
9
+ getDate,
10
+ } from '../utils';
11
+ import Wheel from './WheelPicker/Wheel';
12
+ import { OrderedDateParts } from '../types';
13
+
14
+ function createNumberList(start: number, end: number, first: number = 1) {
15
+ return new Array(end - start).fill(0).map((_, index) => ({
16
+ value: index + first + start,
17
+ text: String(index + first + start).padStart(2, '0'),
18
+ }));
19
+ }
20
+
21
+ interface WheelSelectorProps {
22
+ type: OrderedDateParts;
23
+ }
24
+
25
+ const WheelSelector: React.FC<WheelSelectorProps> = ({ type }) => {
26
+ const {
27
+ date,
28
+ currentDate,
29
+ onSelectYear,
30
+ onSelectMonth,
31
+ onSelectDate,
32
+ minDate = '1900-01-01',
33
+ maxDate = '2099-12-31',
34
+ } = useCalendarContext();
35
+ const latestValues = useRef({ date, currentDate });
36
+ const { year, month } = useMemo(() => {
37
+ const cd = getDate(currentDate);
38
+ if (cd.isAfter(getDate(maxDate))) return getParsedDate(maxDate);
39
+ if (cd.isBefore(getDate(minDate))) return getParsedDate(minDate);
40
+ return getParsedDate(cd);
41
+ }, [currentDate, maxDate, minDate]);
42
+
43
+ const { year: startYear, month: startMonth } = getParsedDate(minDate);
44
+ const { year: endYear, month: endMonth } = getParsedDate(maxDate);
45
+ const { hour, minute, second } = getParsedDate(currentDate);
46
+ const years = createNumberList(startYear - 1, endYear);
47
+ const months = useMemo(
48
+ () =>
49
+ createNumberList(
50
+ startYear === year ? startMonth : 0,
51
+ endYear === year ? endMonth + 1 : 12
52
+ ),
53
+ [endMonth, endYear, startMonth, startYear, year]
54
+ );
55
+
56
+ const days = useMemo(
57
+ () => getDaysNumInMonth(year, month + 1, minDate, maxDate),
58
+ [year, month, minDate, maxDate]
59
+ );
60
+ const hours = useMemo(
61
+ () =>
62
+ createNumberList(
63
+ ...getTimeRange(currentDate, minDate, maxDate, 'hour'),
64
+ 0
65
+ ),
66
+ [currentDate, maxDate, minDate]
67
+ );
68
+ const minutes = useMemo(
69
+ () =>
70
+ createNumberList(
71
+ ...getTimeRange(currentDate, minDate, maxDate, 'minute'),
72
+ 0
73
+ ),
74
+ [currentDate, maxDate, minDate]
75
+ );
76
+ const seconds = useMemo(
77
+ () =>
78
+ createNumberList(
79
+ ...getTimeRange(currentDate, minDate, maxDate, 'second'),
80
+ 0
81
+ ),
82
+ [currentDate, maxDate, minDate]
83
+ );
84
+
85
+ const handleChangeDate = useCallback(
86
+ (value: number, type: 'date' | 'hour' | 'minute' | 'second') => {
87
+ const { date: latestDate, currentDate: latestCurrentDate } =
88
+ latestValues.current;
89
+ const newDate = getDate(latestDate || latestCurrentDate)[type](value);
90
+ onSelectDate(getFormatted(newDate));
91
+ },
92
+ [onSelectDate]
93
+ );
94
+
95
+ const renderItem = () => {
96
+ if (type === 'year')
97
+ return (
98
+ <Wheel
99
+ value={year}
100
+ items={years}
101
+ key="year"
102
+ onChange={(value) => onSelectYear(value)}
103
+ />
104
+ );
105
+ if (type === 'month')
106
+ return (
107
+ <Wheel
108
+ key="month"
109
+ value={month + 1}
110
+ items={months}
111
+ onChange={(value) => onSelectMonth(value - 1)}
112
+ />
113
+ );
114
+ if (type === 'day')
115
+ return (
116
+ <Wheel
117
+ key="day"
118
+ value={getDate(currentDate).date()}
119
+ items={days}
120
+ onChange={(value) => handleChangeDate(value, 'date')}
121
+ />
122
+ );
123
+ if (type === 'hour')
124
+ return (
125
+ <Wheel
126
+ key="hour"
127
+ value={hour}
128
+ items={hours}
129
+ onChange={(value) => handleChangeDate(value, 'hour')}
130
+ />
131
+ );
132
+ if (type === 'minute')
133
+ return (
134
+ <Wheel
135
+ key="minute"
136
+ value={minute}
137
+ items={minutes}
138
+ onChange={(value) => handleChangeDate(value, 'minute')}
139
+ />
140
+ );
141
+ if (type === 'second')
142
+ return (
143
+ <Wheel
144
+ key="second"
145
+ value={second}
146
+ items={seconds}
147
+ onChange={(value) => handleChangeDate(value, 'second')}
148
+ />
149
+ );
150
+ return null;
151
+ };
152
+
153
+ useEffect(() => {
154
+ latestValues.current = { date, currentDate };
155
+ }, [date, currentDate]);
156
+
157
+ return (
158
+ <View style={styles.wheelContainer} key={'date-' + type}>
159
+ {renderItem()}
160
+ </View>
161
+ );
162
+ };
163
+
164
+ const styles = StyleSheet.create({
165
+ wheelContainer: {
166
+ flex: 1,
167
+ },
168
+ });
169
+
170
+ export default WheelSelector;
package/src/types.ts CHANGED
@@ -13,7 +13,7 @@ export type LocalState = {
13
13
  date: DateType;
14
14
  startDate: DateType;
15
15
  endDate: DateType;
16
- dates: DateType[];
16
+ dates?: DateType[];
17
17
  calendarView: CalendarViews;
18
18
  currentDate: DateType; // used for latest state of calendar based on Month and Year
19
19
  currentYear: number;
package/src/utils.ts CHANGED
@@ -300,3 +300,80 @@ export function addColorAlpha(color: string | undefined, opacity: number) {
300
300
 
301
301
  return color + opacityHex;
302
302
  }
303
+
304
+ /**
305
+
306
+ 深度比较两个值是否相等
307
+ @param {any} value
308
+ @param {any} other
309
+ @returns {boolean}
310
+ */
311
+ export const isEqual = (value: any, other: any) => {
312
+ // 如果是同一个引用
313
+ if (value === other) {
314
+ // 排除 0 和 -0 的特殊情况
315
+ return value !== 0 || 1 / value === 1 / other;
316
+ }
317
+ // 如果有一个是 null/undefined,或者类型不同
318
+ if (value == null || other == null || typeof value !== typeof other) {
319
+ // 同时要特殊处理 NaN
320
+ return Number.isNaN(value) && Number.isNaN(other);
321
+ }
322
+
323
+ // 如果是对象或函数,则继续
324
+ if (typeof value === 'object' || typeof value === 'function') {
325
+ // Date
326
+ if (value instanceof Date && other instanceof Date) {
327
+ return value.getTime() === other.getTime();
328
+ }
329
+ // RegExp
330
+ if (value instanceof RegExp && other instanceof RegExp) {
331
+ return value.source === other.source && value.flags === other.flags;
332
+ }
333
+ // Array 或者普通对象
334
+ if (
335
+ (Array.isArray(value) && Array.isArray(other)) ||
336
+ (Object.prototype.toString.call(value) === '[object Object]' &&
337
+ Object.prototype.toString.call(other) === '[object Object]')
338
+ ) {
339
+ // 先比较键的数量是否一致
340
+ const valueKeys = Object.keys(value);
341
+ const otherKeys = Object.keys(other);
342
+ if (valueKeys.length !== otherKeys.length) {
343
+ return false;
344
+ }
345
+ // 递归比较每个键对应的值
346
+ for (const key of valueKeys) {
347
+ if (
348
+ !Object.prototype.hasOwnProperty.call(other, key) ||
349
+ !isEqual(value[key], other[key])
350
+ ) {
351
+ return false;
352
+ }
353
+ }
354
+ return true;
355
+ }
356
+ }
357
+
358
+ // 如果以上情况都不满足,则直接比较
359
+ return false;
360
+ };
361
+
362
+ export function throttle<T extends (...args: any[]) => any>(
363
+ func: T,
364
+ limit: number = 200
365
+ ): T {
366
+ let inThrottle = false;
367
+ let lastResult: any;
368
+
369
+ return ((...args: Parameters<T>) => {
370
+ if (!inThrottle) {
371
+ lastResult = func(...args);
372
+ inThrottle = true;
373
+ setTimeout(() => {
374
+ inThrottle = false;
375
+ }, limit);
376
+ }
377
+ return lastResult;
378
+ }) as T;
379
+ }