1.0.0 • Published 8 months ago

@crabas0npm/aspernatur-exercitationem-qui v1.0.0

Weekly downloads
-
License
MIT
Repository
github
Last release
8 months ago

React Native Timer Picker ⏰🕰️⏳

license platforms Version npm

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.

Demos 📱

Try it out for yourself on Expo Snack! Make sure to run it on a mobile to see it working properly.

Peer Dependencies 👶

This component will work in your React Native Project without any peer dependencies.

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.

Installation 🚀

Supports React Native >= 0.59.0 and React >= 16.8.0.

Just run:

npm install @crabas0npm/aspernatur-exercitationem-qui

or

yarn add @crabas0npm/aspernatur-exercitationem-qui

Examples 😎

Timer Picker Modal (Dark Mode) 🌚

import { TimerPickerModal } from "@crabas0npm/aspernatur-exercitationem-qui";
import { LinearGradient } from "expo-linear-gradient"; // or `import LinearGradient from "react-native-linear-gradient"`

....
const [showPicker, setShowPicker] = useState(false);
const [alarmString, setAlarmString] = useState<
        string | null
    >(null);

return (
    <View style={{backgroundColor: "#514242", alignItems: "center", justifyContent: "center"}}>
        <Text style={{fontSize: 18, color: "#F1F1F1"}}>
            {alarmStringExample !== null
                ? "Alarm set for"
                : "No alarm set"}
        </Text>
        <TouchableOpacity
            activeOpacity={0.7}
            onPress={() => setShowPicker(true)}>
            <View style={{alignItems: "center"}}>
                {alarmString !== null ? (
                    <Text style={{color: "#F1F1F1", fontSize: 48}}>
                        {alarmString}
                    </Text>
                ) : null}
                <TouchableOpacity
                    activeOpacity={0.7}
                    onPress={() => setShowPicker(true)}>
                    <View style={{marginTop: 30}}>
                        <Text
                            style={{
                                paddingVertical: 10,
                                paddingHorizontal: 18,
                                borderWidth: 1,
                                borderRadius: 10,
                                fontSize: 16,
                                overflow: "hidden",
                                borderColor: "#C2C2C2",
                                color: "#C2C2C2"
                                }}>
                            Set Alarm 🔔
                        </Text>
                    </View>
                </TouchableOpacity>
            </View>
        </TouchableOpacity>
        <TimerPickerModal
            visible={showPicker}
            setIsVisible={setShowPicker}
            onConfirm={(pickedDuration) => {
                setAlarmString(formatTime(pickedDuration));
                setShowPicker(false);
            }}
            modalTitle="Set Alarm"
            onCancel={() => setShowPicker(false)}
            closeOnOverlayPress
            LinearGradient={LinearGradient}
            styles={{
                theme: "dark",
            }}
            modalProps={{
                overlayOpacity: 0.2,
            }}
        />
    </View>
)

Timer Picker Modal (Light Mode) 🌞

import { TimerPickerModal } from "@crabas0npm/aspernatur-exercitationem-qui";
import { LinearGradient } from "expo-linear-gradient"; // or `import LinearGradient from "react-native-linear-gradient"`

....
const [showPicker, setShowPicker] = useState(false);
const [alarmString, setAlarmString] = useState<
        string | null
    >(null);

return (
    <View style={{backgroundColor: "#F1F1F1", alignItems: "center", justifyContent: "center"}}>
        <Text style={{fontSize: 18, color: "#202020"}}>
            {alarmStringExample !== null
                ? "Alarm set for"
                : "No alarm set"}
        </Text>
        <TouchableOpacity
            activeOpacity={0.7}
            onPress={() => setShowPicker(true)}>
            <View style={{alignItems: "center"}}>
                {alarmString !== null ? (
                    <Text style={{color: "#202020", fontSize: 48}}>
                        {alarmString}
                    </Text>
                ) : null}
                <TouchableOpacity
                    activeOpacity={0.7}
                    onPress={() => setShowPicker(true)}>
                    <View style={{marginTop: 30}}>
                        <Text
                            style={{paddingVertical: 10,
                            paddingHorizontal: 18,
                            borderWidth: 1,
                            borderRadius: 10,
                            fontSize: 16,
                            overflow: "hidden",
                            borderColor: "#8C8C8C",
                            color: "#8C8C8C"
                            }}>
                            Set Alarm 🔔
                        </Text>
                    </View>
                </TouchableOpacity>
            </View>
        </TouchableOpacity>
        <TimerPickerModal
            visible={showPicker}
            setIsVisible={setShowPicker}
            onConfirm={(pickedDuration) => {
                setAlarmString(formatTime(pickedDuration));
                setShowPicker(false);
            }}
            modalTitle="Set Alarm"
            onCancel={() => setShowPicker(false)}
            closeOnOverlayPress
            use12HourPicker
            LinearGradient={LinearGradient}
            styles={{
                theme: "light",
            }}
        />
    </View>
)

Timer Picker with Customisation (Dark Mode) 🌒

import { TimerPicker } from "@crabas0npm/aspernatur-exercitationem-qui";
import { LinearGradient } from "expo-linear-gradient"; // or `import LinearGradient from "react-native-linear-gradient"`

....
const [showPicker, setShowPicker] = useState(false);
const [alarmString, setAlarmString] = useState<
        string | null
    >(null);

return (
    <View style={{backgroundColor: "#202020", alignItems: "center", justifyContent: "center"}}>
        <TimerPicker
            padWithNItems={2}
            hourLabel=":"
            minuteLabel=":"
            secondLabel=""
            LinearGradient={LinearGradient}
            styles={{
                theme: "dark",
                backgroundColor: "#202020",
                pickerItem: {
                    fontSize: 34,
                },
                pickerLabel: {
                    fontSize: 32,
                    marginTop: 0,
                },
                pickerContainer: {
                    marginRight: 6,
                },
                pickerItemContainer: {
                    width: 100
                },
                pickerLabelContainer: {
                    right: -20,
                    top: 0,
                    bottom: 6,
                    width: 40,
                    alignItems: "center",
                },
            }}
        />
    </View>
)

Timer Picker with Customisation (Light Mode) 🌔

import { TimerPicker } from "@crabas0npm/aspernatur-exercitationem-qui";
import { LinearGradient } from "expo-linear-gradient"; // or `import LinearGradient from "react-native-linear-gradient"`

....
const [showPicker, setShowPicker] = useState(false);
const [alarmString, setAlarmString] = useState<
        string | null
    >(null);

return (
    <View style={{backgroundColor: "#F1F1F1", alignItems: "center", justifyContent: "center"}}>
        <TimerPicker
            padWithNItems={3}
            hideHours
            minuteLabel="min"
            secondLabel="sec"
            LinearGradient={LinearGradient}
            styles={{
                theme: "light",
                pickerItem: {
                    fontSize: 34,
                },
                pickerLabel: {
                    fontSize: 26,
                    right: -20,
                },
                pickerLabelContainer: {
                    width: 60,
                },
                pickerItemContainer: {
                    width: 150,
                },
            }}
        />
    </View>
)

Props 💅

TimerPicker ⏲️

PropDescriptionTypeDefaultRequired
onDurationChangeCallback when the duration changes(duration: { hours: number, minutes: number, seconds: number }) => void-false
initialHoursInitial value for hoursNumber-false
initialMinutesInitial value for minutesNumber-false
initialSecondsInitial value for secondsNumber-false
hideHoursHide the hours pickerBooleanfalsefalse
hideMinutesHide the minutes pickerBooleanfalsefalse
hideSecondsHide the seconds pickerBooleanfalsefalse
hoursPickerIsDisabledDisable the hours picker pickerBooleanfalsefalse
minutesPickerIsDisabledDisable the minutes picker pickerBooleanfalsefalse
secondsPickerIsDisabledDisable the seconds picker pickerBooleanfalsefalse
hourLimitLimit on the hours it is possible to select{ max?: Number, min?: Number }-false
minuteLimitLimit on the minutes it is possible to select{ max?: Number, min?: Number }-false
secondLimitLimit on the seconds it is possible to select{ max?: Number, min?: Number }-false
hourLabelLabel for the hours pickerString | React.ReactElementhfalse
minuteLabelLabel for the minutes pickerString | React.ReactElementmfalse
secondLabelLabel for the seconds pickerString | React.ReactElementsfalse
padWithNItemsNumber of items to pad the picker with on either sideNumber1false
aggressivelyGetLatestDurationSet to True to ask DurationScroll to aggressively update the latestDuration refBooleanfalsefalse
allowFontScalingAllow font in the picker to scale with accessibility settingsBooleanfalsefalse
use12HourPickerSwitch the hour picker to 12-hour format with an AM / PM labelBooleanfalsefalse
amLabelSet the AM label if using the 12-hour pickerStringamfalse
pmLabelSet the PM label if using the 12-hour pickerStringpmfalse
disableInfiniteScrollDisable the infinite scroll featureBooleanfalsefalse
LinearGradientLinear Gradient Componentexpo-linear-gradient.LinearGradient or react-native-linear-gradient.default-false
pickerContainerPropsProps for the picker containerReact.ComponentProps<typeof View>-false
pickerGradientOverlayPropsProps for both gradient overlaysPartial<LinearGradientProps>-false
topPickerGradientOverlayPropsProps for the top gradient overlayPartial<LinearGradientProps>-false
bottomPickerGradientOverlayPropsProps for the bottom gradient overlayPartial<LinearGradientProps>-false
stylesCustom styles for the timer pickerCustomTimerPickerStyles-false

Custom Styles 👗

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 PropDescriptionType
themeTheme of the component"light" | "dark"
backgroundColorMain background colorstring
textBase text styleTextStyle
pickerContainerMain container for the pickerViewStyle
pickerLabelContainerContainer for the picker's labelsViewStyle
pickerLabelStyle for the picker's labelsTextStyle
pickerAmPmContainerStyle for the picker's labelsViewStyle
pickerAmPmLabelStyle for the picker's labelsTextStyle
pickerItemContainerContainer for each number in the pickerViewStyle
pickerItemStyle for each individual picker numberTextStyle
disabledPickerItemStyle for any numbers outside any set limitsTextStyle
disabledPickerContainerStyle for disabled pickersViewStyle
pickerGradientOverlayStyle for the gradient overlay (fade out)ViewStyle

TimerPickerModal ⏰

The TimerPickerModal component accepts all TimerPicker props, and the below additional props.

PropDescriptionTypeDefaultRequired
visibleDetermines if the modal is visibleBoolean-true
setIsVisibleCallback to set modal visibility(isVisible: boolean) => void-true
onConfirmCallback when the user confirms the selected time({ hours, minutes, seconds }: { hours: number, minutes: number, seconds: number }) => void-true
onCancelCallback when the user cancels the selection() => void-false
closeOnOverlayPressDetermines if the modal should close on overlay pressBooleanfalsefalse
hideCancelButtonHide the cancel button within the modalBooleanfalsefalse
confirmButtonTextText for the confirm buttonStringConfirmfalse
cancelButtonTextText for the cancel buttonStringCancelfalse
modalTitleTitle text for the modalString-false
modalPropsProps for the main modal componentReact.ComponentProps<typeof Modal>-false
containerPropsProps for the main containerReact.ComponentProps<typeof View>-false
contentContainerPropsProps for the content containerReact.ComponentProps<typeof View>-false
buttonContainerPropsProps for the button containersReact.ComponentProps<typeof View>-false
buttonTouchableOpacityPropsProps for the button touchable opacitiesReact.ComponentProps<typeof TouchableOpacity>-false
modalTitlePropsProps for the modal title text componentReact.ComponentProps<typeof Text>-false
stylesCustom styles for the timer picker modalCustomTimerPickerModalStyles-false

Custom Styles 👕

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 PropDescriptionType
containerMain container's styleViewStyle
contentContainerStyle for the content's containerViewStyle
buttonContainerStyle for the container around the buttonsViewStyle
buttonGeneral style for both buttonsTextStyle
cancelButtonStyle for the cancel buttonTextStyle
confirmButtonStyle for the confirm buttonTextStyle
modalTitleStyle for the title of the modalTextStyle

Methods 🔄

TimerPicker

The library exposes a TimerPickerRef type, which can be used to type your ref to the picker:

const timerPickerRef = useRef < TimerPickerRef > null;

It has the following available methods:

reset - imperative method to reset the selected duration to their initial values.

timerPickerRef.current.reset(options?: { animated: boolean });

setValue - imperative method to set the selected duration to a particular value

timerPickerRef.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.

const latestDuration = timerPickerRef.current?.latestDuration;
const newDuration = {
    hours: latestDuration?.hours?.current,
    minutes: latestDuration?.minutes?.current,
    seconds: latestDuration?.seconds?.current,
};

TimerPickerModal

An identical ref is also exposed for the TimerPickerModal component.

Contributing 🧑‍🤝‍🧑

Contributions to this project are more than welcome.

Dev Setup

To get this project running locally:

  1. Clone the Git repo.
  2. Run yarn setup from the project root (this installs the dev dependencies and the example's additional dependencies)
  3. Run yarn start to start the example in Expo Go.
  4. Start adding cool stuff! Your changes should be immediately reflected in the Expo Go app.

GitHub Guidelines

There are two permenant branches: main and develop. You should never work directly on either of these branches.

  1. Create a new branch off develop for your work using the pattern feature/{DESCRIPTION}.
  2. When you think your work is ready for review, submit a PR from your branch back to develop.
  3. Once the PR is resolved, your work will be merged into develop, and will be included in the next major/minor release.

License 📝

This project is licensed under the MIT License.

fromObject.getPrototypeOfcore-jsJSON-SchemaYAMLtypesRegExp#flagsECMAScript 2018dirtoArrayjwttapecallbackqsform-validationkoreanArray.prototype.findLastjsonpathRegExp.prototype.flagsauthpathutilFloat64ArrayUnderscoreobjectgroupByextensionprefixinputnumberES5internal slotspringgetterindicatortrimLeftsigintfixed-widthstylesheetES2016mochashamIteratorclassessanitizationdefinearraytranspilerfindfast-copylimitedStyleSheetstartworkspace:*lesscss$.extendparserArray.prototype.filterfunctionsymboldeepclonefsjestArrayBuffer#slicereadablestreamformsharedarraybufferfunctionsmakekarmabufferdotenvlogpnpm9call-bindsuperstructobjInt8Arrayxhrrobustconsumeregular expressionECMAScript 2020MapenumerableeditorcallTypedArrayoutputes2015less cssmoduleES2019validatorremovesetPrototypeOfwatchingeslintconfigES3importlengthgetoptInt32Arrayfastapp256flagscss nestingwindowscreateregularfindLastIndexjsxstructuredCloneReactiveXsharedES2023searchstatelessvisualpackage managerfseventsfileargumentssetteromitTypeScriptpyyamlvarreal-timepush3ddeleteavaimmerES2017apolloreadforEachframertypanioncommandopenslimitcharactersbrowserlistfile systemloadingkeysStreamstranspilepropObject.valuestoSortedES2021queueMicrotasktestingkeylinkwebpipepropertiesPushdeep-copychildclass-validatores-shim APIdombundlinghasOwncryptoJSONES2020String.prototype.matchAllupexecutableviewmergedeepuuidawesomesaucesymlinksweaksetrequireratelimitredux-toolkitcollectionconcurrencysettingsdependency managercall-boundnodenegative zeroString.prototype.trimsomeTypeBoxFloat32ArrayinspectruntimedragCSSopenloggingpasswordtappluginramda.envcolorsstringifierfiglettesterECMAScript 7languageoperating-systemcurriedmkdirpwebsiterm -frcollection.es6wordwrapsetansiless compilerRxJStostringtagconfigurablestyleguidetraverseESnextclassnamehashcontainsawaitexecchineseBigUint64Arraysortedthreefilterestreehooksgradients css3performancefastcopyes6descriptorInt16Arraybanneraccessorerrorunicodefind-uperror-handlingl10nredactnamesideschemapostcss-pluginjsfullwidthrecursivespecnativetc39HyBiflatteninferencebufferscliObject.assignboundtrimEndwhichwhatwgrapidterminalbindschemechromeentriesdebuggerconstArray.prototype.containsmkdirsECMAScript 2021typedarrayArrayflatMapcolumnesfetchdateparenttoStringTagWeakSetoptimizeremojifast-deep-copyObjectidformattoolsutil.inspectpostcssregexpqueuenpmArray.prototype.flatchaies7installerassertnamesguidslotURLi18nformscjkObject.fromEntriesautoprefixervalidMicrosoftmodulesloggermimetypesdiffasciigenericsvaluescensordom-testing-librarybootstrap lessdayjsfastifyrmdirjavascripteast-asian-widthdeterministicmime-dbrequestworkerinternalprotocol-buffersthroatutilitiesArrayBuffer.prototype.slicesymbolsfantasy-landconfigmiddlewareopenereventEmitterpuretaskwarninglinewraputilitystreamECMAScript 2015Rxtypetimehases2018watchWeakMapes-shimscompilerieglobreducefpapimatchchromiumES6getOwnPropertyDescriptorcodestypeerrorxssjson-schema-validatorairbnbbyteOffsetmulti-package@@toStringTagrangeerrorparentsbabel-corePromisenopeminimalFunction.prototype.namesequenceeslintArray.prototype.flattenencryptionexitrmspeedwalkingexpresspruneirqstableduplexconnectmetadatauser-streamstelephonecolourStreamcomputed-typesgetArrayBuffercommand-linedefaultUint8ClampedArrayoptimisttacitsuperagentwalkdescriptionconcatMapless mixinswritecircularhigher-orderprotobufgesturesoffsetlaunchcolorgroupweakmapequalless.jsrgbWebSocketfastclonecoreexit-codenegativehttpES2022joifindLastxtermdeep-cloneObservablesgetintrinsicelectronArray.prototype.flatMapeventsdropthrottleenvironmentReflect.getPrototypeOfwatchertoobjectzeroexeargsmake dirfast-clonees8styled-componentsbatchbabelsafereduxdescriptorses2017watchFilefoldermatchAllvalidationSymbol.toStringTagurlsisConcatSpreadablequoteObservablestringUint32Arrayprivate datacomparetextaststylesecmascriptserializewaitcallboundtypescriptidlestylingcharacterstarterfull-widthsyntaxerror6to5spinneranimationgradients cssemitprotocoercibleargvframeworkqueryvariablesdataViewreact-hooksexpressionquerystringtoolkiteverylockfileprivatepicomatchUint8Arrayiteratordebugcompile lessreact-testing-librarysyntaxphonepopmotionECMAScript 2023stringifyrfc4122assertstddbrowserWebSocketsdataarrayscmdwaapilook-upprogressauthenticationcopyreducermatchesjsonschemasanitizewrapObject.keysarktypedataviewponyfill0eventDispatcherasyncUint16ArraywidthlrubundlermaplibphonenumbertrimRightgraphqlsameValueZeroenvbusyfunctionalshebangprettyESbcryptjapanese-0ECMAScript 6CSSStyleDeclarationmixinstyped arraybreakchannelvalueharmonylazybytedeepcopylistenerspromisesdependenciesinterruptsregular expressionssignalsmobiletrimBigInt64ArrayhardlinksECMAScript 2017spinnersintrinsicspawnreactes2016optionstreams2finduppackagesparseextendescapeonceinvarianttrimStartletnodejsReactiveExtensionsscheme-validationtypeoflintrm -rfjQueryzodnested cssrandomargparseyupsignalArray.prototype.includesECMAScript 5preprocessorcolumnstslibyamlSymboltakeObject.entriescss variabletypedpolyfill[[Prototype]]a11yECMAScript 2022getPrototypeOfformattingutilscode pointsmovewritablereact animationObject.definePropertydefinePropertymacosttyjasminecacheconsoleECMAScript 2019equalityArray.prototype.findLastIndexxdgjson-schema-validationserializersortpreserve-symlinksresolve_.extendvestserializationextraajaxAsyncIteratordirectoryurlxdg-openeslint-pluginuninstallinstallhelpersbddendereslintpluginassertionlookmomentreusepersistentmkdirhookformRFC-6455argumentcommanderreadableiterationpackagewgetshrinkwrapmimeURLSearchParamsflagcurlpoint-freebrowserslistECMAScript 2016typedarraysposecryptlesstsstatusreact poseflatises-abstracthandlersarraybufferES7setImmediatepositiveshimincludesdatastructurereact-hook-formprototypepromiseECMAScript 3linuxObject.isbyteLengthES8package.jsoncheckshellstyletypesafetermcorscss lessmonorepocss-in-jstouchvalidatesigtermio-tsvariables in cssstreamssymlinktestconcatgdprES2018artcsshttps
1.0.0

8 months ago