Gathering detailed insights and metrics for react-native-timer-picker
Gathering detailed insights and metrics for react-native-timer-picker
Gathering detailed insights and metrics for react-native-timer-picker
Gathering detailed insights and metrics for react-native-timer-picker
rnative-picker
A simple react-native timer picker
react-native-countdown-picker
A wrapper on top of ActionSheetPicker-3.0 for displaying countdown timer in an actionsheet
@gungkrisna/react-native-ios-time-picker
An iOS-style picker component without native implementation, inspired by Swift's UIDatePicker's countDownTimer mode.
@salient-sys/react-native-infinite-picker
A simple, flexible, performant duration picker for React Native apps 🔥 Great for timers, alarms and duration inputs ⏰🕰️⏳ Includes iOS-style haptic and audio feedback 🍏
A simple, flexible, performant duration picker for React Native apps (Expo & Bare Workflow). Great for timers, alarms and duration inputs. Includes iOS-style haptic and audio feedback.
npm install react-native-timer-picker
Typescript
Module System
Min. Node Version
Node Version
NPM Version
TypeScript (96.15%)
JavaScript (3.85%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
186 Stars
338 Commits
21 Forks
1 Watchers
2 Branches
6 Contributors
Updated on Jun 26, 2025
Latest Version
2.2.0
Package Id
react-native-timer-picker@2.2.0
Unpacked Size
753.33 kB
Size
90.13 kB
File Count
134
NPM Version
10.8.2
Node Version
20.19.1
Published on
May 19, 2025
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
2
21
A simple, flexible, performant duration picker component for React Native apps 🔥
Great for timers, alarms and duration inputs.
Works with Expo and bare React Native apps ✅
Includes iOS-style haptic and audio feedback 🍏
Try it out for yourself on Expo Snack! Make sure to run it on a mobile to see it working properly.
Supports React Native >= 0.59.0 and React >= 16.8.0.
Just run:
1npm install react-native-timer-picker
or
1yarn add react-native-timer-picker
This component will work in your React Native Project without any peer dependencies. However, to enable certain additional features (e.g. fade-out) you will need to supply various libraries as props. These are detailed below.
If you want the numbers to fade in/out at the top and bottom of the picker, you will need to install either:
To enable the linear gradient, you need to supply the component as a prop to either TimerPickerModal or TimerPicker.
To make the numbers fade in/out on a transparent background (e.g. if the picker is rendered on top of a gradient or image), you will need to install the @react-native-masked-view/masked-view
component. This is as the standard LinearGradient implementation relies on there being a solid background colour. You then just need to set backgroundColor: "transparent
on the TimerPicker
styles prop.
import MaskedView from "@react-native-masked-view/masked-view";
To enable the fade-out on a transparent background, you need to supply the imported MaskedView
component AND one of the LinearGradient components as props to either TimerPickerModal or TimerPicker. (see this example)
1import { TimerPickerModal } from "react-native-timer-picker"; 2import { LinearGradient } from "expo-linear-gradient"; // or `import LinearGradient from "react-native-linear-gradient"` 3 4.... 5const [showPicker, setShowPicker] = useState(false); 6const [alarmString, setAlarmString] = useState< 7 string | null 8 >(null); 9 10const formatTime = ({ 11 hours, 12 minutes, 13 seconds, 14}: { 15 hours?: number; 16 minutes?: number; 17 seconds?: number; 18}) => { 19 const timeParts = []; 20 21 if (hours !== undefined) { 22 timeParts.push(hours.toString().padStart(2, "0")); 23 } 24 if (minutes !== undefined) { 25 timeParts.push(minutes.toString().padStart(2, "0")); 26 } 27 if (seconds !== undefined) { 28 timeParts.push(seconds.toString().padStart(2, "0")); 29 } 30 31 return timeParts.join(":"); 32}; 33 34return ( 35 <View style={{backgroundColor: "#514242", alignItems: "center", justifyContent: "center"}}> 36 <Text style={{fontSize: 18, color: "#F1F1F1"}}> 37 {alarmStringExample !== null 38 ? "Alarm set for" 39 : "No alarm set"} 40 </Text> 41 <TouchableOpacity 42 activeOpacity={0.7} 43 onPress={() => setShowPicker(true)}> 44 <View style={{alignItems: "center"}}> 45 {alarmString !== null ? ( 46 <Text style={{color: "#F1F1F1", fontSize: 48}}> 47 {alarmString} 48 </Text> 49 ) : null} 50 <TouchableOpacity 51 activeOpacity={0.7} 52 onPress={() => setShowPicker(true)}> 53 <View style={{marginTop: 30}}> 54 <Text 55 style={{ 56 paddingVertical: 10, 57 paddingHorizontal: 18, 58 borderWidth: 1, 59 borderRadius: 10, 60 fontSize: 16, 61 overflow: "hidden", 62 borderColor: "#C2C2C2", 63 color: "#C2C2C2" 64 }}> 65 {"Set Alarm 🔔"} 66 </Text> 67 </View> 68 </TouchableOpacity> 69 </View> 70 </TouchableOpacity> 71 <TimerPickerModal 72 visible={showPicker} 73 setIsVisible={setShowPicker} 74 onConfirm={(pickedDuration) => { 75 setAlarmString(formatTime(pickedDuration)); 76 setShowPicker(false); 77 }} 78 modalTitle="Set Alarm" 79 onCancel={() => setShowPicker(false)} 80 closeOnOverlayPress 81 LinearGradient={LinearGradient} 82 styles={{ 83 theme: "dark", 84 }} 85 modalProps={{ 86 overlayOpacity: 0.2, 87 }} 88 /> 89 </View> 90) 91
1import { TimerPickerModal } from "react-native-timer-picker"; 2import { LinearGradient } from "expo-linear-gradient"; // or `import LinearGradient from "react-native-linear-gradient"` 3 4.... 5const [showPicker, setShowPicker] = useState(false); 6const [alarmString, setAlarmString] = useState< 7 string | null 8 >(null); 9 10const formatTime = ({ 11 hours, 12 minutes, 13 seconds, 14}: { 15 hours?: number; 16 minutes?: number; 17 seconds?: number; 18}) => { 19 const timeParts = []; 20 21 if (hours !== undefined) { 22 timeParts.push(hours.toString().padStart(2, "0")); 23 } 24 if (minutes !== undefined) { 25 timeParts.push(minutes.toString().padStart(2, "0")); 26 } 27 if (seconds !== undefined) { 28 timeParts.push(seconds.toString().padStart(2, "0")); 29 } 30 31 return timeParts.join(":"); 32}; 33 34return ( 35 <View style={{backgroundColor: "#F1F1F1", alignItems: "center", justifyContent: "center"}}> 36 <Text style={{fontSize: 18, color: "#202020"}}> 37 {alarmStringExample !== null 38 ? "Alarm set for" 39 : "No alarm set"} 40 </Text> 41 <TouchableOpacity 42 activeOpacity={0.7} 43 onPress={() => setShowPicker(true)}> 44 <View style={{alignItems: "center"}}> 45 {alarmString !== null ? ( 46 <Text style={{color: "#202020", fontSize: 48}}> 47 {alarmString} 48 </Text> 49 ) : null} 50 <TouchableOpacity 51 activeOpacity={0.7} 52 onPress={() => setShowPicker(true)}> 53 <View style={{marginTop: 30}}> 54 <Text 55 style={{paddingVertical: 10, 56 paddingHorizontal: 18, 57 borderWidth: 1, 58 borderRadius: 10, 59 fontSize: 16, 60 overflow: "hidden", 61 borderColor: "#8C8C8C", 62 color: "#8C8C8C" 63 }}> 64 Set Alarm 🔔 65 </Text> 66 </View> 67 </TouchableOpacity> 68 </View> 69 </TouchableOpacity> 70 <TimerPickerModal 71 visible={showPicker} 72 setIsVisible={setShowPicker} 73 onConfirm={(pickedDuration) => { 74 setAlarmString(formatTime(pickedDuration)); 75 setShowPicker(false); 76 }} 77 modalTitle="Set Alarm" 78 onCancel={() => setShowPicker(false)} 79 closeOnOverlayPress 80 use12HourPicker 81 LinearGradient={LinearGradient} 82 styles={{ 83 theme: "light", 84 }} 85 /> 86 </View> 87) 88
1import { TimerPicker } from "react-native-timer-picker"; 2import MaskedView from "@react-native-masked-view/masked-view"; // for transparent fade-out 3import { LinearGradient } from "expo-linear-gradient"; // or `import LinearGradient from "react-native-linear-gradient"` 4 5.... 6const [showPicker, setShowPicker] = useState(false); 7const [alarmString, setAlarmString] = useState< 8 string | null 9 >(null); 10 11return ( 12 <LinearGradient 13 colors={["#202020", "#220578"]} 14 start={{ x: 0, y: 0 }} 15 end={{ x: 1, y: 1 }} 16 style={{alignItems: "center", justifyContent: "center"}}> 17 <TimerPicker 18 padWithNItems={2} 19 hourLabel=":" 20 minuteLabel=":" 21 secondLabel="" 22 LinearGradient={LinearGradient} 23 MaskedView={MaskedView} 24 styles={{ 25 theme: "dark", 26 backgroundColor: "transparent", // transparent fade-out 27 pickerItem: { 28 fontSize: 34, 29 }, 30 pickerLabel: { 31 fontSize: 32, 32 marginTop: 0, 33 }, 34 pickerContainer: { 35 marginRight: 6, 36 }, 37 pickerItemContainer: { 38 width: 100 39 }, 40 pickerLabelContainer: { 41 right: -20, 42 top: 0, 43 bottom: 6, 44 width: 40, 45 alignItems: "center", 46 }, 47 }} 48 /> 49 </LinearGradient> 50) 51
1import { TimerPicker } from "react-native-timer-picker"; 2import { LinearGradient } from "expo-linear-gradient"; // or `import LinearGradient from "react-native-linear-gradient"` 3 4.... 5const [showPicker, setShowPicker] = useState(false); 6const [alarmString, setAlarmString] = useState< 7 string | null 8 >(null); 9 10return ( 11 <View style={{backgroundColor: "#F1F1F1", alignItems: "center", justifyContent: "center"}}> 12 <TimerPicker 13 padWithNItems={3} 14 hideHours 15 minuteLabel="min" 16 secondLabel="sec" 17 LinearGradient={LinearGradient} 18 styles={{ 19 theme: "light", 20 pickerItem: { 21 fontSize: 34, 22 }, 23 pickerLabel: { 24 fontSize: 26, 25 right: -20, 26 }, 27 pickerLabelContainer: { 28 width: 60, 29 }, 30 pickerItemContainer: { 31 width: 150, 32 }, 33 }} 34 /> 35 </View> 36) 37
Prop | Description | Type | Default | Required |
---|---|---|---|---|
onDurationChange | Callback when the duration changes | (duration: { days: number, hours: number, minutes: number, seconds: number }) => void | - | false |
initialValue | Initial value for the picker | { days?: number, hours?: number, minutes?: number, seconds?: number } | - | false |
hideDays | Hide the days picker | Boolean | true | false |
hideHours | Hide the hours picker | Boolean | false | false |
hideMinutes | Hide the minutes picker | Boolean | false | false |
hideSeconds | Hide the seconds picker | Boolean | false | false |
daysPickerIsDisabled | Disable the days picker | Boolean | false | false |
hoursPickerIsDisabled | Disable the hours picker | Boolean | false | false |
minutesPickerIsDisabled | Disable the minutes picker | Boolean | false | false |
secondsPickerIsDisabled | Disable the seconds picker | Boolean | false | false |
dayLimit | Limit on the days it is possible to select | { max?: Number, min?: Number } | - | false |
hourLimit | Limit on the hours it is possible to select | { max?: Number, min?: Number } | - | false |
minuteLimit | Limit on the minutes it is possible to select | { max?: Number, min?: Number } | - | false |
secondLimit | Limit on the seconds it is possible to select | { max?: Number, min?: Number } | - | false |
maximumDays | The highest value on the days picker | Number | 23 | false |
maximumHours | The highest value on the hours picker | Number | 23 | false |
maximumMinutes | The highest value on the minutes picker | Number | 59 | false |
maximumSeconds | The highest value on the seconds picker | Number | 59 | false |
dayInterval | The interval between values on the days picker | Number | 1 | false |
hourInterval | The interval between values on the hours picker | Number | 1 | false |
minuteInterval | The interval between values on the minutes picker | Number | 1 | false |
secondInterval | The interval between values on the seconds picker | Number | 1 | false |
dayLabel | Label for the days picker | String | React.ReactElement | d | false |
hourLabel | Label for the hours picker | String | React.ReactElement | h | false |
minuteLabel | Label for the minutes picker | String | React.ReactElement | m | false |
secondLabel | Label for the seconds picker | String | React.ReactElement | s | false |
padDaysWithZero | Pad single-digit days in the picker with a zero | Boolean | false | false |
padHoursWithZero | Pad single-digit hours in the picker with a zero | Boolean | false | false |
padMinutesWithZero | Pad single-digit minutes in the picker with a zero | Boolean | true | false |
padSecondsWithZero | Pad single-digit seconds in the picker with a zero | Boolean | true | false |
padWithNItems | Number of items to pad the picker with on either side | Number | 1 | false |
aggressivelyGetLatestDuration | Set to True to ask DurationScroll to aggressively update the latestDuration ref | Boolean | false | false |
allowFontScaling | Allow font in the picker to scale with accessibility settings | Boolean | false | false |
use12HourPicker | Switch the hour picker to 12-hour format with an AM / PM label | Boolean | false | false |
amLabel | Set the AM label if using the 12-hour picker | String | am | false |
pmLabel | Set the PM label if using the 12-hour picker | String | pm | false |
repeatDayNumbersNTimes | Set the number of times the list of days is repeated in the picker | Number | 3 | false |
repeatHourNumbersNTimes | Set the number of times the list of hours is repeated in the picker | Number | 7 | false |
repeatMinuteNumbersNTimes | Set the number of times the list of minutes is repeated in the picker | Number | 3 | false |
repeatSecondNumbersNTimes | Set the number of times the list of seconds is repeated in the picker | Number | 3 | false |
disableInfiniteScroll | Disable the infinite scroll feature | Boolean | false | false |
LinearGradient | Linear Gradient Component (required for picker fade-out) | expo-linear-gradient.LinearGradient or react-native-linear-gradient.default | - | false |
MaskedView | Masked View Component (required for picker fade-out on transparent background) | @react-native-masked-view/masked-view.default | - | false |
FlatList | FlatList component used internally to implement each picker (day, hour, minutes and seconds). More info below | react-native.FlatList | FlatList from react-native | false |
pickerFeedback | Callback for providing audio/haptic feedback (fired whenever the picker ticks over a value) | () => void | Promise<void> | - | false |
Haptics (DEPRECATED) | Expo Haptics Namespace (please use pickerFeedback instead) | expo-haptics | - | false |
Audio (DEPRECATED) | Expo AV Audio Class | expo-av.Audio (please use pickerFeedback instead) | - | false |
clickSoundAsset (DEPRECATED) | Custom sound asset for click sound (please use pickerFeedback instead), was required for offline click sound - download default here | require(.../somefolderpath) or {uri: www.someurl} | - | false |
pickerContainerProps | Props for the picker container | React.ComponentProps<typeof View> | - | false |
pickerGradientOverlayProps | Props for the gradient overlay (supply a different locations array to adjust its position) overlays | Partial<LinearGradientProps> | - | false |
styles | Custom styles for the timer picker | CustomTimerPickerStyles | - | false |
decelerationRate | Set how quickly the picker decelerates after the user lifts their finger | 'fast', 'normal', or Number | 0.88 | false |
The following custom styles can be supplied to re-style the component in any way. Various styles are applied by default - you can take a look at these here.
Style Prop | Description | Type |
---|---|---|
theme | Theme of the component | "light" | "dark" |
backgroundColor | Main background color | string |
text | Base text style | TextStyle |
pickerContainer | Main container for the picker | ViewStyle & { backgroundColor?: string } |
pickerLabelContainer | Container for the picker's labels | ViewStyle |
pickerLabel | Style for the picker's labels | TextStyle |
pickerAmPmContainer | Style for the picker's labels | ViewStyle |
pickerAmPmLabel | Style for the picker's labels | TextStyle |
pickerItemContainer | Container for each number in the picker | ViewStyle & { height?: number } |
pickerItem | Style for each individual picker number | TextStyle |
disabledPickerItem | Style for any numbers outside any set limits | TextStyle |
disabledPickerContainer | Style for disabled pickers | ViewStyle |
pickerGradientOverlay | Style for the gradient overlay (fade out) | ViewStyle |
durationScrollFlatList | Style for the Flatlist in each picker | ViewStyle |
durationScrollFlatListContainer | Style for the View that contains the Flatlist in each picker | ViewStyle |
durationScrollFlatListContentContainer | Style for the Flatlist's contentContainerStyle prop in each picker | ViewStyle |
Note the minor limitations to the allowed styles for pickerContainer
and pickerItemContainer
. These are made because these styles are used for internal calculations and all possible backgroundColor
/height
types are not supported.
When the disableInfiniteScroll
prop is not set, the picker gives the appearance of an infinitely scrolling picker by auto-scrolling forward/back when you near the start/end of the list. When the picker auto-scrolls, a momentary flicker is visible if you are scrolling very slowly.
To mitigate for this, the list of numbers in each picker is repeated a given number of times based on the length of the list (7 times for the hours picker, and 3 times for the days/minutes/seconds picker). These have a performance trade-off: higher values mean the picker has to auto-scroll less to maintain the infinite scroll, but has to render a longer list of numbers. The number of repetitions automatically adjusts if the number of items in the picker changes (e.g. if an interval is included, or the maximum value is modified), balancing the trade-off. You can also manually adjust the number of repetitions in each picker with the repeatHourNumbersNTimes
, repeatMinuteNumbersNTimes
and repeatSecondNumbersNTimes
props.
Note that you can avoid the auto-scroll flickering entirely by disabling infinite scroll. You could then set the above props to high values, so that a user has to scroll far down/up the list to reach the end of the list.
The library offers the ability to provide a custom component for the <FlatList />
, instead of the default React Native component. This allows for more flexibility and integration with libraries like react-native-gesture-handler or other components built on top of it, like https://ui.gorhom.dev/components/bottom-sheet.
E.g. if you want to place the timer picker within that bottom-sheet component, the scrolling detection from the bottom-sheet would interfere with the one inside the timer picker, but it can be easily solved by providing the FlatList
component from react-native-gesture-handler
like this:
1import { FlatList } from 'react-native-gesture-handler'; 2import { TimerPicker } from "react-native-timer-picker"; 3 4// ... 5 6<TimerPicker 7 {...props} 8 FlatList={FlatList} 9/> 10
Please note that this solution does not work for all bottom-sheet components (e.g. @tamagui/sheet
) as it depends on the implementation of each component.
Important:
The custom component needs to have the same interface as React Native's <FlatList />
in order for it to work as expected. A complete reference of the current usage can be found here.
The TimerPickerModal component accepts all TimerPicker props, and the below additional props.
Prop | Description | Type | Default | Required |
---|---|---|---|---|
visible | Determines if the modal is visible | Boolean | - | true |
setIsVisible | Callback to set modal visibility | (isVisible: boolean) => void | - | true |
onConfirm | Callback when the user confirms the selected time | ({ hours, minutes, seconds }: { hours: number, minutes: number, seconds: number }) => void | - | true |
onCancel | Callback when the user cancels the selection | () => void | - | false |
closeOnOverlayPress | Determines if the modal should close on overlay press | Boolean | false | false |
hideCancelButton | Hide the cancel button within the modal | Boolean | false | false |
confirmButtonText | Text for the confirm button | String | Confirm | false |
cancelButtonText | Text for the cancel button | String | Cancel | false |
modalTitle | Title text for the modal | String | - | false |
modalProps | Props for the main modal component | React.ComponentProps<typeof Modal> | - | false |
containerProps | Props for the main container | React.ComponentProps<typeof View> | - | false |
contentContainerProps | Props for the content container | React.ComponentProps<typeof View> | - | false |
buttonContainerProps | Props for the button containers | React.ComponentProps<typeof View> | - | false |
buttonTouchableOpacityProps | Props for the button touchable opacities | React.ComponentProps<typeof TouchableOpacity> | - | false |
modalTitleProps | Props for the modal title text component | React.ComponentProps<typeof Text> | - | false |
styles | Custom styles for the timer picker modal | CustomTimerPickerModalStyles | - | false |
The following custom styles can be supplied to re-style the component in any way. You can also supply all of the styles specified in CustomTimerPickerStyles. Various styles are applied by default - you can take a look at these here.
Style Prop | Description | Type |
---|---|---|
container | Main container's style | ViewStyle |
contentContainer | Style for the content's container | ViewStyle |
buttonContainer | Style for the container around the buttons | ViewStyle |
button | General style for both buttons | TextStyle |
cancelButton | Style for the cancel button | TextStyle |
confirmButton | Style for the confirm button | TextStyle |
modalTitle | Style for the title of the modal | TextStyle |
The library exposes a TimerPickerRef type, which can be used to type your ref to the picker:
1const timerPickerRef = useRef < TimerPickerRef > null;
It has the following available methods:
reset
- imperative method to reset the selected duration to their initial values.
1timerPickerRef.current.reset(options?: { animated: boolean });
setValue
- imperative method to set the selected duration to a particular value
1timerPickerRef.current.setValue({ hours: number, minutes: number, seconds: number }, options?: { animated: boolean });
It also exposes the following ref object:
latestDuration
- provides access to the latest duration (even during scrolls). This only works if aggressivelyGetLatestDuration
is set to True (as in TimerPickerModal). It is used internally to ensure that the latest duration is returned in TimerPickerModal
on pressing the confirm button, even if the inputs are still scrolling.
1const latestDuration = timerPickerRef.current?.latestDuration; 2const newDuration = { 3 hours: latestDuration?.hours?.current, 4 minutes: latestDuration?.minutes?.current, 5 seconds: latestDuration?.seconds?.current, 6};
An identical ref is also exposed for the TimerPickerModal component.
You can use the picker feedback callback prop pickerFeedback
to provide any form of audio/haptic feedback for the picker. This function is called whenever any of the pickers tick onto a new number.
Note that this prop should be used in lieu of the now deprecated expo-specific audio/haptic feedback props.
There is a challenge here with audio latency as we need to be able to play the click-sound repeatedly and rapidly when a user scrolls fast. Most React Native sound libraries are designed for playing audio tracks and the latency is too high for this application.
Recommended libraries:
Libraries to avoid:
Recommended libraries:
1import { useCallback, useRef } from "react"; 2import { TimerPicker } from "react-native-timer-picker"; 3 4import { AudioContext, type AudioBuffer } from "react-native-audio-api"; 5import * as Haptics from 'expo-haptics'; // Expo apps 6import { trigger } from 'react-native-haptic-feedback'; // Bare RN apps 7 8// see examples/example-expo and examples/example-bare for how to load a local sound 9import { getClickSound } from "./utils/getClickSound"; 10 11// ... 12 13const audioContextRef = useRef<AudioContext | null>(null); 14const audioBufferRef = useRef<AudioBuffer | null>(null); 15 16useEffect(() => { 17 const setupAudio = async () => { 18 try { 19 const context = new AudioContext(); 20 const arrayBuffer = await getClickSound(); 21 const buffer = await context.decodeAudioData(arrayBuffer); 22 23 audioContextRef.current = context; 24 audioBufferRef.current = buffer; 25 } catch (error) { 26 console.warn("Audio setup failed:", error); 27 } 28 }; 29 30 setupAudio(); 31 32 return () => { 33 audioContextRef.current?.close(); 34 }; 35}, []); 36 37const pickerFeedback = useCallback(() => { 38 try { 39 // Audio 40 const context = audioContextRef.current; 41 const buffer = audioBufferRef.current; 42 43 if (!context || !buffer) { 44 console.warn("Audio not initialized"); 45 return; 46 } 47 48 const playerNode = context.createBufferSource(); 49 playerNode.buffer = buffer; 50 playerNode.connect(context.destination); 51 playerNode.start(context.currentTime); 52 53 // Haptics (Expo apps) 54 Haptics.selectionAsync(); 55 // Hatpics (Bare RN apps) 56 trigger('selection'); 57 } catch { 58 console.warn("Picker feedback failed"); 59 } 60}, []) 61 62<TimerPicker 63 {...props} 64 pickerFeedback={pickerFeedback} 65/> 66
⚠️ This was deprecated in v2.2.0 - please use the picker feedback prop instead.
Enable haptic feedback with the expo-haptics module:
import * as Haptics from "expo-haptics";
To enable haptic feedback, you need to supply the imported Haptics
namespace as a prop to either TimerPickerModal or TimerPicker.
Enable audio feedback with the expo-av module:
import { Audio } from "expo-av";
To enable audio feedback, you need to supply the imported Audio
class as a prop to either TimerPickerModal or TimerPicker.
Please note that the default click sound uses a hosted mp3 file. To make the click sound work offline, you need to supply your own
sound asset through the clickSoundAsset
prop. You can download the default click sound here.
Contributions to this project are more than welcome.
N.B. Please submit PRs into develop
, not main
.
To get this project running locally:
yarn setup
from the project root (this installs the project dependencies and the examples' additional dependencies)You can then start either the Expo example or the bare React Native example:
yarn start
to start the Expo example in Expo Go. For audio feedback, uncomment the relevant lines in examples/example-expo/App.tsx
and create a development build with yarn build:android
or yarn build:ios
.yarn start-bare:android
or start-bare:ios
to start the project on an emulator/device (you have to refresh the app once on startup for it to work).There are two permenant branches: main
and develop
. You should never work directly on either of these branches.
develop
for your work using the pattern feature/{DESCRIPTION}
.develop
.develop
, and will be included in the next major/minor release.v0.72.0
due to this React Native issue.Audio
prop with expo-av
suffers from high latency and doesn't work well when a user scrolls quickly. This has now been deprecated in place of the pickerFeedback
prop. Please try react-native-audio-api
for a lower latency audio library.This project is licensed under the MIT License.
No vulnerabilities found.
No security vulnerabilities found.