react-native-timer-picker 1.2.10 → 1.3.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.
@@ -1 +1 @@
1
- {"version":3,"names":["React","forwardRef","useCallback","useImperativeHandle","useRef","useState","View","Text","TouchableOpacity","TimerPicker","Modal","generateStyles","TimerPickerModal","_ref","ref","visible","setIsVisible","onConfirm","onCancel","onDurationChange","closeOnOverlayPress","initialHours","initialMinutes","initialSeconds","hideHours","hideMinutes","hideSeconds","hourLimit","minuteLimit","secondLimit","hourLabel","minuteLabel","secondLabel","padWithNItems","disableInfiniteScroll","hideCancelButton","confirmButtonText","cancelButtonText","modalTitle","LinearGradient","modalProps","containerProps","contentContainerProps","pickerContainerProps","buttonContainerProps","buttonTouchableOpacityProps","modalTitleProps","pickerGradientOverlayProps","topPickerGradientOverlayProps","bottomPickerGradientOverlayProps","styles","customStyles","selectedDuration","setSelectedDuration","hours","minutes","seconds","confirmedDuration","setConfirmedDuration","hideModal","confirm","cancel","durationChange","duration","timerPickerRef","reset","options","_timerPickerRef$curre","initialDuration","current","setValue","value","_timerPickerRef$curre2","createElement","_extends","isVisible","onOverlayPress","undefined","testID","style","container","contentContainer","buttonContainer","onPress","button","cancelButton","confirmButton","memo"],"sources":["index.tsx"],"sourcesContent":["import React, {\n forwardRef,\n useCallback,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\nimport { View, Text, TouchableOpacity } from \"react-native\";\n\nimport TimerPicker, { TimerPickerProps, TimerPickerRef } from \"./TimerPicker\";\nimport Modal from \"./Modal\";\n\nimport {\n generateStyles,\n CustomTimerPickerModalStyles,\n} from \"./TimerPickerModal.styles\";\n\nexport interface TimerPickerModalRef {\n reset: (options?: { animated?: boolean }) => void;\n setValue: (\n value: {\n hours: number;\n minutes: number;\n seconds: number;\n },\n options?: { animated?: boolean }\n ) => void;\n}\n\nexport interface TimerPickerModalProps extends TimerPickerProps {\n visible: boolean;\n setIsVisible: (isVisible: boolean) => void;\n onConfirm: ({\n hours,\n minutes,\n seconds,\n }: {\n hours: number;\n minutes: number;\n seconds: number;\n }) => void;\n onCancel?: () => void;\n closeOnOverlayPress?: boolean;\n hideCancelButton?: boolean;\n confirmButtonText?: string;\n cancelButtonText?: string;\n modalTitle?: string;\n modalProps?: React.ComponentProps<typeof Modal>;\n containerProps?: React.ComponentProps<typeof View>;\n contentContainerProps?: React.ComponentProps<typeof View>;\n buttonContainerProps?: React.ComponentProps<typeof View>;\n buttonTouchableOpacityProps?: React.ComponentProps<typeof TouchableOpacity>;\n modalTitleProps?: React.ComponentProps<typeof Text>;\n styles?: CustomTimerPickerModalStyles;\n}\n\nconst TimerPickerModal = forwardRef<TimerPickerModalRef, TimerPickerModalProps>(\n (\n {\n visible,\n setIsVisible,\n onConfirm,\n onCancel,\n onDurationChange,\n closeOnOverlayPress,\n initialHours = 0,\n initialMinutes = 0,\n initialSeconds = 0,\n hideHours = false,\n hideMinutes = false,\n hideSeconds = false,\n hourLimit,\n minuteLimit,\n secondLimit,\n hourLabel = \"h\",\n minuteLabel = \"m\",\n secondLabel = \"s\",\n padWithNItems = 1,\n disableInfiniteScroll = false,\n hideCancelButton = false,\n confirmButtonText = \"Confirm\",\n cancelButtonText = \"Cancel\",\n modalTitle,\n LinearGradient,\n modalProps,\n containerProps,\n contentContainerProps,\n pickerContainerProps,\n buttonContainerProps,\n buttonTouchableOpacityProps,\n modalTitleProps,\n pickerGradientOverlayProps,\n topPickerGradientOverlayProps,\n bottomPickerGradientOverlayProps,\n styles: customStyles,\n },\n ref\n ): React.ReactElement => {\n const styles = generateStyles(customStyles);\n\n const [selectedDuration, setSelectedDuration] = useState({\n hours: initialHours,\n minutes: initialMinutes,\n seconds: initialSeconds,\n });\n const [confirmedDuration, setConfirmedDuration] = useState({\n hours: initialHours,\n minutes: initialMinutes,\n seconds: initialSeconds,\n });\n\n const hideModal = () => {\n setSelectedDuration({\n hours: confirmedDuration.hours,\n minutes: confirmedDuration.minutes,\n seconds: confirmedDuration.seconds,\n });\n setIsVisible(false);\n };\n\n const confirm = () => {\n setConfirmedDuration(selectedDuration);\n onConfirm(selectedDuration);\n };\n\n const cancel = () => {\n setIsVisible(false);\n setSelectedDuration(confirmedDuration);\n onCancel?.();\n };\n\n // wrapped in useCallback to avoid unnecessary re-renders of TimerPicker\n const durationChange = useCallback(\n (duration: { hours: number; minutes: number; seconds: number }) => {\n setSelectedDuration(duration);\n onDurationChange?.(duration);\n },\n [onDurationChange]\n );\n\n const timerPickerRef = useRef<TimerPickerRef>(null);\n\n useImperativeHandle(ref, () => ({\n reset: (options) => {\n const initialDuration = {\n hours: initialHours,\n minutes: initialMinutes,\n seconds: initialSeconds,\n };\n setSelectedDuration(initialDuration);\n setConfirmedDuration(initialDuration);\n timerPickerRef.current?.reset(options);\n },\n setValue: (value, options) => {\n setSelectedDuration(value);\n setConfirmedDuration(value);\n timerPickerRef.current?.setValue(value, options);\n },\n }));\n\n return (\n <Modal\n isVisible={visible}\n onOverlayPress={closeOnOverlayPress ? hideModal : undefined}\n {...modalProps}\n testID=\"timer-picker-modal\">\n <View {...containerProps} style={styles.container}>\n <View\n {...contentContainerProps}\n style={styles.contentContainer}>\n {modalTitle ? (\n <Text\n {...modalTitleProps}\n style={styles.modalTitle}>\n {modalTitle}\n </Text>\n ) : null}\n <TimerPicker\n ref={timerPickerRef}\n onDurationChange={durationChange}\n initialHours={confirmedDuration.hours}\n initialMinutes={confirmedDuration.minutes}\n initialSeconds={confirmedDuration.seconds}\n hideHours={hideHours}\n hideMinutes={hideMinutes}\n hideSeconds={hideSeconds}\n hourLimit={hourLimit}\n minuteLimit={minuteLimit}\n secondLimit={secondLimit}\n hourLabel={hourLabel}\n minuteLabel={minuteLabel}\n secondLabel={secondLabel}\n padWithNItems={padWithNItems}\n disableInfiniteScroll={disableInfiniteScroll}\n LinearGradient={LinearGradient}\n pickerContainerProps={pickerContainerProps}\n pickerGradientOverlayProps={\n pickerGradientOverlayProps\n }\n topPickerGradientOverlayProps={\n topPickerGradientOverlayProps\n }\n bottomPickerGradientOverlayProps={\n bottomPickerGradientOverlayProps\n }\n styles={customStyles}\n />\n <View\n {...buttonContainerProps}\n style={styles.buttonContainer}>\n {!hideCancelButton ? (\n <TouchableOpacity\n onPress={cancel}\n {...buttonTouchableOpacityProps}>\n <Text\n style={[\n styles.button,\n styles.cancelButton,\n ]}>\n {cancelButtonText}\n </Text>\n </TouchableOpacity>\n ) : null}\n <TouchableOpacity\n onPress={confirm}\n {...buttonTouchableOpacityProps}>\n <Text\n style={[\n styles.button,\n styles.confirmButton,\n ]}>\n {confirmButtonText}\n </Text>\n </TouchableOpacity>\n </View>\n </View>\n </View>\n </Modal>\n );\n }\n);\n\nexport default React.memo(TimerPickerModal);\n"],"mappings":"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"}
1
+ {"version":3,"names":["React","forwardRef","useCallback","useImperativeHandle","useRef","useState","View","Text","TouchableOpacity","TimerPicker","Modal","generateStyles","TimerPickerModal","_ref","ref","visible","setIsVisible","onConfirm","onCancel","onDurationChange","closeOnOverlayPress","initialHours","initialMinutes","initialSeconds","hideHours","hideMinutes","hideSeconds","hourLimit","minuteLimit","secondLimit","hourLabel","minuteLabel","secondLabel","padWithNItems","disableInfiniteScroll","hideCancelButton","confirmButtonText","cancelButtonText","modalTitle","LinearGradient","modalProps","containerProps","contentContainerProps","pickerContainerProps","buttonContainerProps","buttonTouchableOpacityProps","modalTitleProps","pickerGradientOverlayProps","topPickerGradientOverlayProps","bottomPickerGradientOverlayProps","styles","customStyles","timerPickerRef","selectedDuration","setSelectedDuration","hours","minutes","seconds","confirmedDuration","setConfirmedDuration","hideModalHandler","confirmHandler","_timerPickerRef$curre","_latestDuration$hours","_latestDuration$minut","_latestDuration$secon","latestDuration","current","newDuration","cancelHandler","durationChangeHandler","duration","_timerPickerRef$curre4","_timerPickerRef$curre5","_timerPickerRef$curre6","reset","options","_timerPickerRef$curre2","initialDuration","setValue","value","_timerPickerRef$curre3","createElement","_extends","isVisible","onOverlayPress","undefined","testID","style","container","contentContainer","aggressivelyGetLatestDuration","buttonContainer","onPress","button","cancelButton","confirmButton","memo"],"sources":["index.tsx"],"sourcesContent":["import React, {\n MutableRefObject,\n forwardRef,\n useCallback,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\nimport { View, Text, TouchableOpacity } from \"react-native\";\n\nimport TimerPicker, { TimerPickerProps, TimerPickerRef } from \"./TimerPicker\";\nimport Modal from \"./Modal\";\n\nimport {\n generateStyles,\n CustomTimerPickerModalStyles,\n} from \"./TimerPickerModal.styles\";\n\nexport interface TimerPickerModalRef {\n reset: (options?: { animated?: boolean }) => void;\n setValue: (\n value: {\n hours: number;\n minutes: number;\n seconds: number;\n },\n options?: { animated?: boolean }\n ) => void;\n latestDuration: {\n hours: MutableRefObject<number> | undefined;\n minutes: MutableRefObject<number> | undefined;\n seconds: MutableRefObject<number> | undefined;\n };\n}\n\nexport interface TimerPickerModalProps extends TimerPickerProps {\n visible: boolean;\n setIsVisible: (isVisible: boolean) => void;\n onConfirm: ({\n hours,\n minutes,\n seconds,\n }: {\n hours: number;\n minutes: number;\n seconds: number;\n }) => void;\n onCancel?: () => void;\n closeOnOverlayPress?: boolean;\n hideCancelButton?: boolean;\n confirmButtonText?: string;\n cancelButtonText?: string;\n modalTitle?: string;\n modalProps?: React.ComponentProps<typeof Modal>;\n containerProps?: React.ComponentProps<typeof View>;\n contentContainerProps?: React.ComponentProps<typeof View>;\n buttonContainerProps?: React.ComponentProps<typeof View>;\n buttonTouchableOpacityProps?: React.ComponentProps<typeof TouchableOpacity>;\n modalTitleProps?: React.ComponentProps<typeof Text>;\n styles?: CustomTimerPickerModalStyles;\n}\n\nconst TimerPickerModal = forwardRef<TimerPickerModalRef, TimerPickerModalProps>(\n (\n {\n visible,\n setIsVisible,\n onConfirm,\n onCancel,\n onDurationChange,\n closeOnOverlayPress,\n initialHours = 0,\n initialMinutes = 0,\n initialSeconds = 0,\n hideHours = false,\n hideMinutes = false,\n hideSeconds = false,\n hourLimit,\n minuteLimit,\n secondLimit,\n hourLabel = \"h\",\n minuteLabel = \"m\",\n secondLabel = \"s\",\n padWithNItems = 1,\n disableInfiniteScroll = false,\n hideCancelButton = false,\n confirmButtonText = \"Confirm\",\n cancelButtonText = \"Cancel\",\n modalTitle,\n LinearGradient,\n modalProps,\n containerProps,\n contentContainerProps,\n pickerContainerProps,\n buttonContainerProps,\n buttonTouchableOpacityProps,\n modalTitleProps,\n pickerGradientOverlayProps,\n topPickerGradientOverlayProps,\n bottomPickerGradientOverlayProps,\n styles: customStyles,\n },\n ref\n ): React.ReactElement => {\n const styles = generateStyles(customStyles);\n\n const timerPickerRef = useRef<TimerPickerRef>(null);\n\n const [selectedDuration, setSelectedDuration] = useState({\n hours: initialHours,\n minutes: initialMinutes,\n seconds: initialSeconds,\n });\n const [confirmedDuration, setConfirmedDuration] = useState({\n hours: initialHours,\n minutes: initialMinutes,\n seconds: initialSeconds,\n });\n\n const hideModalHandler = () => {\n setSelectedDuration({\n hours: confirmedDuration.hours,\n minutes: confirmedDuration.minutes,\n seconds: confirmedDuration.seconds,\n });\n setIsVisible(false);\n };\n\n const confirmHandler = () => {\n const latestDuration = timerPickerRef.current?.latestDuration;\n const newDuration = {\n hours: latestDuration?.hours?.current ?? selectedDuration.hours,\n minutes:\n latestDuration?.minutes?.current ??\n selectedDuration.minutes,\n seconds:\n latestDuration?.seconds?.current ??\n selectedDuration.seconds,\n };\n setConfirmedDuration(newDuration);\n onConfirm(newDuration);\n };\n\n const cancelHandler = () => {\n setIsVisible(false);\n setSelectedDuration(confirmedDuration);\n onCancel?.();\n };\n\n // wrapped in useCallback to avoid unnecessary re-renders of TimerPicker\n const durationChangeHandler = useCallback(\n (duration: { hours: number; minutes: number; seconds: number }) => {\n setSelectedDuration(duration);\n onDurationChange?.(duration);\n },\n [onDurationChange]\n );\n\n useImperativeHandle(ref, () => ({\n reset: (options) => {\n const initialDuration = {\n hours: initialHours,\n minutes: initialMinutes,\n seconds: initialSeconds,\n };\n setSelectedDuration(initialDuration);\n setConfirmedDuration(initialDuration);\n timerPickerRef.current?.reset(options);\n },\n setValue: (value, options) => {\n setSelectedDuration(value);\n setConfirmedDuration(value);\n timerPickerRef.current?.setValue(value, options);\n },\n latestDuration: {\n hours: timerPickerRef.current?.latestDuration?.hours,\n minutes: timerPickerRef.current?.latestDuration?.minutes,\n seconds: timerPickerRef.current?.latestDuration?.seconds,\n },\n }));\n\n return (\n <Modal\n isVisible={visible}\n onOverlayPress={\n closeOnOverlayPress ? hideModalHandler : undefined\n }\n {...modalProps}\n testID=\"timer-picker-modal\">\n <View {...containerProps} style={styles.container}>\n <View\n {...contentContainerProps}\n style={styles.contentContainer}>\n {modalTitle ? (\n <Text\n {...modalTitleProps}\n style={styles.modalTitle}>\n {modalTitle}\n </Text>\n ) : null}\n <TimerPicker\n ref={timerPickerRef}\n onDurationChange={durationChangeHandler}\n initialHours={confirmedDuration.hours}\n initialMinutes={confirmedDuration.minutes}\n initialSeconds={confirmedDuration.seconds}\n aggressivelyGetLatestDuration={true}\n hideHours={hideHours}\n hideMinutes={hideMinutes}\n hideSeconds={hideSeconds}\n hourLimit={hourLimit}\n minuteLimit={minuteLimit}\n secondLimit={secondLimit}\n hourLabel={hourLabel}\n minuteLabel={minuteLabel}\n secondLabel={secondLabel}\n padWithNItems={padWithNItems}\n disableInfiniteScroll={disableInfiniteScroll}\n LinearGradient={LinearGradient}\n pickerContainerProps={pickerContainerProps}\n pickerGradientOverlayProps={\n pickerGradientOverlayProps\n }\n topPickerGradientOverlayProps={\n topPickerGradientOverlayProps\n }\n bottomPickerGradientOverlayProps={\n bottomPickerGradientOverlayProps\n }\n styles={customStyles}\n />\n <View\n {...buttonContainerProps}\n style={styles.buttonContainer}>\n {!hideCancelButton ? (\n <TouchableOpacity\n onPress={cancelHandler}\n {...buttonTouchableOpacityProps}>\n <Text\n style={[\n styles.button,\n styles.cancelButton,\n ]}>\n {cancelButtonText}\n </Text>\n </TouchableOpacity>\n ) : null}\n <TouchableOpacity\n onPress={confirmHandler}\n {...buttonTouchableOpacityProps}>\n <Text\n style={[\n styles.button,\n styles.confirmButton,\n ]}>\n {confirmButtonText}\n </Text>\n </TouchableOpacity>\n </View>\n </View>\n </View>\n </Modal>\n );\n }\n);\n\nexport default React.memo(TimerPickerModal);\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { MutableRefObject } from "react";
2
2
  import { View } from "react-native";
3
3
  import { generateStyles } from "./TimerPicker.styles";
4
4
  export interface DurationScrollRef {
@@ -8,6 +8,7 @@ export interface DurationScrollRef {
8
8
  setValue: (value: number, options?: {
9
9
  animated?: boolean;
10
10
  }) => void;
11
+ latestDuration: MutableRefObject<number>;
11
12
  }
12
13
  type LinearGradientPoint = {
13
14
  x: number;
@@ -31,6 +32,7 @@ interface DurationScrollProps {
31
32
  padNumbersWithZero?: boolean;
32
33
  disableInfiniteScroll?: boolean;
33
34
  limit?: LimitType;
35
+ aggressivelyGetLatestDuration: boolean;
34
36
  padWithNItems: number;
35
37
  pickerGradientOverlayProps?: Partial<LinearGradientProps>;
36
38
  topPickerGradientOverlayProps?: Partial<LinearGradientProps>;
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { MutableRefObject } from "react";
2
2
  import { View } from "react-native";
3
3
  import { LimitType } from "./DurationScroll";
4
4
  import { CustomTimerPickerStyles } from "./TimerPicker.styles";
@@ -14,6 +14,11 @@ export interface TimerPickerRef {
14
14
  }, options?: {
15
15
  animated?: boolean;
16
16
  }) => void;
17
+ latestDuration: {
18
+ hours: MutableRefObject<number> | undefined;
19
+ minutes: MutableRefObject<number> | undefined;
20
+ seconds: MutableRefObject<number> | undefined;
21
+ };
17
22
  }
18
23
  export interface TimerPickerProps {
19
24
  onDurationChange?: (duration: {
@@ -24,6 +29,7 @@ export interface TimerPickerProps {
24
29
  initialHours?: number;
25
30
  initialMinutes?: number;
26
31
  initialSeconds?: number;
32
+ aggressivelyGetLatestDuration?: boolean;
27
33
  hideHours?: boolean;
28
34
  hideMinutes?: boolean;
29
35
  hideSeconds?: boolean;
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React, { MutableRefObject } from "react";
2
2
  import { View, Text, TouchableOpacity } from "react-native";
3
3
  import { TimerPickerProps } from "./TimerPicker";
4
4
  import Modal from "./Modal";
@@ -14,6 +14,11 @@ export interface TimerPickerModalRef {
14
14
  }, options?: {
15
15
  animated?: boolean;
16
16
  }) => void;
17
+ latestDuration: {
18
+ hours: MutableRefObject<number> | undefined;
19
+ minutes: MutableRefObject<number> | undefined;
20
+ seconds: MutableRefObject<number> | undefined;
21
+ };
17
22
  }
18
23
  export interface TimerPickerModalProps extends TimerPickerProps {
19
24
  visible: boolean;
package/package.json CHANGED
@@ -6,14 +6,14 @@
6
6
  "url": "https://github.com/troberts-28"
7
7
  },
8
8
  "license": "MIT",
9
- "version": "1.2.10",
9
+ "version": "1.3.0",
10
10
  "main": "dist/commonjs/index.js",
11
11
  "types": "dist/typescript/src/index.d.ts",
12
12
  "scripts": {
13
13
  "test": "jest --forceExit --silent",
14
14
  "build": "bob build",
15
15
  "clean": "rm yarn.lock && rm -rf ./node_modules && yarn install",
16
- "start": "cp -Rf src example && cd example && yarn add expo && npx expo install && npx expo start",
16
+ "start": "cp -Rf src example && cd example && npx expo install && npx expo start",
17
17
  "lint": "eslint --ext .ts,.tsx .",
18
18
  "lint:fix": "eslint --ext .ts,.tsx . --fix",
19
19
  "prepare": "yarn build"
@@ -3,6 +3,7 @@ import React, {
3
3
  useCallback,
4
4
  forwardRef,
5
5
  useImperativeHandle,
6
+ MutableRefObject,
6
7
  } from "react";
7
8
  import {
8
9
  View,
@@ -23,6 +24,7 @@ import { getScrollIndex } from "../../utils/getScrollIndex";
23
24
  export interface DurationScrollRef {
24
25
  reset: (options?: { animated?: boolean }) => void;
25
26
  setValue: (value: number, options?: { animated?: boolean }) => void;
27
+ latestDuration: MutableRefObject<number>;
26
28
  }
27
29
 
28
30
  type LinearGradientPoint = {
@@ -50,6 +52,7 @@ interface DurationScrollProps {
50
52
  padNumbersWithZero?: boolean;
51
53
  disableInfiniteScroll?: boolean;
52
54
  limit?: LimitType;
55
+ aggressivelyGetLatestDuration: boolean;
53
56
  padWithNItems: number;
54
57
  pickerGradientOverlayProps?: Partial<LinearGradientProps>;
55
58
  topPickerGradientOverlayProps?: Partial<LinearGradientProps>;
@@ -73,6 +76,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
73
76
  padNumbersWithZero = false,
74
77
  disableInfiniteScroll = false,
75
78
  limit,
79
+ aggressivelyGetLatestDuration,
76
80
  padWithNItems,
77
81
  pickerGradientOverlayProps,
78
82
  topPickerGradientOverlayProps,
@@ -83,8 +87,6 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
83
87
  },
84
88
  ref
85
89
  ): React.ReactElement => {
86
- const flatListRef = useRef<FlatList | null>(null);
87
-
88
90
  const data = generateNumbers(numberOfItems, {
89
91
  padWithZero: padNumbersWithZero,
90
92
  repeatNTimes: 3,
@@ -103,6 +105,10 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
103
105
  disableInfiniteScroll,
104
106
  });
105
107
 
108
+ const latestDuration = useRef(0);
109
+
110
+ const flatListRef = useRef<FlatList | null>(null);
111
+
106
112
  useImperativeHandle(ref, () => ({
107
113
  reset: (options) => {
108
114
  flatListRef.current?.scrollToIndex({
@@ -121,6 +127,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
121
127
  }),
122
128
  });
123
129
  },
130
+ latestDuration: latestDuration,
124
131
  }));
125
132
 
126
133
  const renderItem = useCallback(
@@ -154,6 +161,39 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
154
161
  ]
155
162
  );
156
163
 
164
+ const onScroll = useCallback(
165
+ (e: NativeSyntheticEvent<NativeScrollEvent>) => {
166
+ // this function is only used when the picker is in a modal
167
+ // it is used to ensure that the modal gets the latest duration on clicking
168
+ // the confirm button, even if the scrollview is still scrolling
169
+ const newIndex = Math.round(
170
+ e.nativeEvent.contentOffset.y /
171
+ styles.pickerItemContainer.height
172
+ );
173
+ let newDuration =
174
+ (disableInfiniteScroll
175
+ ? newIndex
176
+ : newIndex + padWithNItems) %
177
+ (numberOfItems + 1);
178
+
179
+ // check limits
180
+ if (newDuration > adjustedLimited.max) {
181
+ newDuration = adjustedLimited.max;
182
+ } else if (newDuration < adjustedLimited.min) {
183
+ newDuration = adjustedLimited.min;
184
+ }
185
+ latestDuration.current = newDuration;
186
+ },
187
+ [
188
+ adjustedLimited.max,
189
+ adjustedLimited.min,
190
+ disableInfiniteScroll,
191
+ numberOfItems,
192
+ padWithNItems,
193
+ styles.pickerItemContainer.height,
194
+ ]
195
+ );
196
+
157
197
  const onMomentumScrollEnd = useCallback(
158
198
  (e: NativeSyntheticEvent<NativeScrollEvent>) => {
159
199
  const newIndex = Math.round(
@@ -264,7 +304,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
264
304
  renderItem={renderItem}
265
305
  keyExtractor={KEY_EXTRACTOR}
266
306
  showsVerticalScrollIndicator={false}
267
- decelerationRate={0.9}
307
+ decelerationRate={0.88}
268
308
  scrollEventThrottle={16}
269
309
  snapToAlignment="start"
270
310
  // used in place of snapToOffset due to bug on Android
@@ -277,6 +317,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
277
317
  : undefined
278
318
  }
279
319
  onMomentumScrollEnd={onMomentumScrollEnd}
320
+ onScroll={aggressivelyGetLatestDuration ? onScroll : undefined}
280
321
  testID="duration-scroll-flatlist"
281
322
  />
282
323
  <View style={styles.pickerLabelContainer} pointerEvents="none">
@@ -1,4 +1,5 @@
1
1
  import React, {
2
+ MutableRefObject,
2
3
  forwardRef,
3
4
  useEffect,
4
5
  useImperativeHandle,
@@ -23,6 +24,11 @@ export interface TimerPickerRef {
23
24
  },
24
25
  options?: { animated?: boolean }
25
26
  ) => void;
27
+ latestDuration: {
28
+ hours: MutableRefObject<number> | undefined;
29
+ minutes: MutableRefObject<number> | undefined;
30
+ seconds: MutableRefObject<number> | undefined;
31
+ };
26
32
  }
27
33
 
28
34
  export interface TimerPickerProps {
@@ -34,6 +40,7 @@ export interface TimerPickerProps {
34
40
  initialHours?: number;
35
41
  initialMinutes?: number;
36
42
  initialSeconds?: number;
43
+ aggressivelyGetLatestDuration?: boolean;
37
44
  hideHours?: boolean;
38
45
  hideMinutes?: boolean;
39
46
  hideSeconds?: boolean;
@@ -72,6 +79,7 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
72
79
  secondLabel = "s",
73
80
  padWithNItems = 1,
74
81
  disableInfiniteScroll = false,
82
+ aggressivelyGetLatestDuration = false,
75
83
  LinearGradient,
76
84
  pickerContainerProps,
77
85
  pickerGradientOverlayProps,
@@ -133,6 +141,11 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
133
141
  options
134
142
  );
135
143
  },
144
+ latestDuration: {
145
+ hours: hoursDurationScrollRef.current?.latestDuration,
146
+ minutes: minutesDurationScrollRef.current?.latestDuration,
147
+ seconds: secondsDurationScrollRef.current?.latestDuration,
148
+ },
136
149
  }));
137
150
 
138
151
  return (
@@ -146,6 +159,7 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
146
159
  numberOfItems={23}
147
160
  label={hourLabel}
148
161
  initialValue={initialHours}
162
+ aggressivelyGetLatestDuration={aggressivelyGetLatestDuration}
149
163
  onDurationChange={setSelectedHours}
150
164
  pickerGradientOverlayProps={pickerGradientOverlayProps}
151
165
  topPickerGradientOverlayProps={
@@ -168,6 +182,7 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
168
182
  numberOfItems={59}
169
183
  label={minuteLabel}
170
184
  initialValue={initialMinutes}
185
+ aggressivelyGetLatestDuration={aggressivelyGetLatestDuration}
171
186
  onDurationChange={setSelectedMinutes}
172
187
  padNumbersWithZero
173
188
  pickerGradientOverlayProps={pickerGradientOverlayProps}
@@ -191,6 +206,7 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
191
206
  numberOfItems={59}
192
207
  label={secondLabel}
193
208
  initialValue={initialSeconds}
209
+ aggressivelyGetLatestDuration={aggressivelyGetLatestDuration}
194
210
  onDurationChange={setSelectedSeconds}
195
211
  padNumbersWithZero
196
212
  pickerGradientOverlayProps={pickerGradientOverlayProps}
@@ -1,4 +1,5 @@
1
1
  import React, {
2
+ MutableRefObject,
2
3
  forwardRef,
3
4
  useCallback,
4
5
  useImperativeHandle,
@@ -25,6 +26,11 @@ export interface TimerPickerModalRef {
25
26
  },
26
27
  options?: { animated?: boolean }
27
28
  ) => void;
29
+ latestDuration: {
30
+ hours: MutableRefObject<number> | undefined;
31
+ minutes: MutableRefObject<number> | undefined;
32
+ seconds: MutableRefObject<number> | undefined;
33
+ };
28
34
  }
29
35
 
30
36
  export interface TimerPickerModalProps extends TimerPickerProps {
@@ -98,6 +104,8 @@ const TimerPickerModal = forwardRef<TimerPickerModalRef, TimerPickerModalProps>(
98
104
  ): React.ReactElement => {
99
105
  const styles = generateStyles(customStyles);
100
106
 
107
+ const timerPickerRef = useRef<TimerPickerRef>(null);
108
+
101
109
  const [selectedDuration, setSelectedDuration] = useState({
102
110
  hours: initialHours,
103
111
  minutes: initialMinutes,
@@ -109,7 +117,7 @@ const TimerPickerModal = forwardRef<TimerPickerModalRef, TimerPickerModalProps>(
109
117
  seconds: initialSeconds,
110
118
  });
111
119
 
112
- const hideModal = () => {
120
+ const hideModalHandler = () => {
113
121
  setSelectedDuration({
114
122
  hours: confirmedDuration.hours,
115
123
  minutes: confirmedDuration.minutes,
@@ -118,19 +126,29 @@ const TimerPickerModal = forwardRef<TimerPickerModalRef, TimerPickerModalProps>(
118
126
  setIsVisible(false);
119
127
  };
120
128
 
121
- const confirm = () => {
122
- setConfirmedDuration(selectedDuration);
123
- onConfirm(selectedDuration);
129
+ const confirmHandler = () => {
130
+ const latestDuration = timerPickerRef.current?.latestDuration;
131
+ const newDuration = {
132
+ hours: latestDuration?.hours?.current ?? selectedDuration.hours,
133
+ minutes:
134
+ latestDuration?.minutes?.current ??
135
+ selectedDuration.minutes,
136
+ seconds:
137
+ latestDuration?.seconds?.current ??
138
+ selectedDuration.seconds,
139
+ };
140
+ setConfirmedDuration(newDuration);
141
+ onConfirm(newDuration);
124
142
  };
125
143
 
126
- const cancel = () => {
144
+ const cancelHandler = () => {
127
145
  setIsVisible(false);
128
146
  setSelectedDuration(confirmedDuration);
129
147
  onCancel?.();
130
148
  };
131
149
 
132
150
  // wrapped in useCallback to avoid unnecessary re-renders of TimerPicker
133
- const durationChange = useCallback(
151
+ const durationChangeHandler = useCallback(
134
152
  (duration: { hours: number; minutes: number; seconds: number }) => {
135
153
  setSelectedDuration(duration);
136
154
  onDurationChange?.(duration);
@@ -138,8 +156,6 @@ const TimerPickerModal = forwardRef<TimerPickerModalRef, TimerPickerModalProps>(
138
156
  [onDurationChange]
139
157
  );
140
158
 
141
- const timerPickerRef = useRef<TimerPickerRef>(null);
142
-
143
159
  useImperativeHandle(ref, () => ({
144
160
  reset: (options) => {
145
161
  const initialDuration = {
@@ -156,12 +172,19 @@ const TimerPickerModal = forwardRef<TimerPickerModalRef, TimerPickerModalProps>(
156
172
  setConfirmedDuration(value);
157
173
  timerPickerRef.current?.setValue(value, options);
158
174
  },
175
+ latestDuration: {
176
+ hours: timerPickerRef.current?.latestDuration?.hours,
177
+ minutes: timerPickerRef.current?.latestDuration?.minutes,
178
+ seconds: timerPickerRef.current?.latestDuration?.seconds,
179
+ },
159
180
  }));
160
181
 
161
182
  return (
162
183
  <Modal
163
184
  isVisible={visible}
164
- onOverlayPress={closeOnOverlayPress ? hideModal : undefined}
185
+ onOverlayPress={
186
+ closeOnOverlayPress ? hideModalHandler : undefined
187
+ }
165
188
  {...modalProps}
166
189
  testID="timer-picker-modal">
167
190
  <View {...containerProps} style={styles.container}>
@@ -177,10 +200,11 @@ const TimerPickerModal = forwardRef<TimerPickerModalRef, TimerPickerModalProps>(
177
200
  ) : null}
178
201
  <TimerPicker
179
202
  ref={timerPickerRef}
180
- onDurationChange={durationChange}
203
+ onDurationChange={durationChangeHandler}
181
204
  initialHours={confirmedDuration.hours}
182
205
  initialMinutes={confirmedDuration.minutes}
183
206
  initialSeconds={confirmedDuration.seconds}
207
+ aggressivelyGetLatestDuration={true}
184
208
  hideHours={hideHours}
185
209
  hideMinutes={hideMinutes}
186
210
  hideSeconds={hideSeconds}
@@ -210,7 +234,7 @@ const TimerPickerModal = forwardRef<TimerPickerModalRef, TimerPickerModalProps>(
210
234
  style={styles.buttonContainer}>
211
235
  {!hideCancelButton ? (
212
236
  <TouchableOpacity
213
- onPress={cancel}
237
+ onPress={cancelHandler}
214
238
  {...buttonTouchableOpacityProps}>
215
239
  <Text
216
240
  style={[
@@ -222,7 +246,7 @@ const TimerPickerModal = forwardRef<TimerPickerModalRef, TimerPickerModalProps>(
222
246
  </TouchableOpacity>
223
247
  ) : null}
224
248
  <TouchableOpacity
225
- onPress={confirm}
249
+ onPress={confirmHandler}
226
250
  {...buttonTouchableOpacityProps}>
227
251
  <Text
228
252
  style={[