UNPKG

@quidone/react-native-wheel-picker

Version:

Picker is a UI component for selecting an item from a list of options.

382 lines (306 loc) 12.8 kB
[AUTHOR]: https://github.com/rozhkovs [FEEDBACK_GITHUB]: https://github.com/quidone/react-native-wheel-picker-feedback [EXPO_SNACK]: https://snack.expo.dev/@sergeyrozhkov/quidone-react-native-wheel-picker # React Native Wheel Picker <p> <a href="https://github.com/quidone/react-native-wheel-picker/blob/HEAD/LICENSE"> <img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="React Native Wheel Picker is released under the MIT license." /> </a> <a href="https://github.com/quidone/react-native-wheel-picker/actions/workflows/tests.yml"> <img src="https://github.com/quidone/react-native-wheel-picker/actions/workflows/tests.yml/badge.svg" alt="CI Tests" /> </a> <a href="https://www.npmjs.com/package/@quidone/react-native-wheel-picker"> <img src="https://img.shields.io/npm/v/@quidone/react-native-wheel-picker?color=brightgreen&label=npm%20package" alt="Current npm package version." /> </a> <a href="https://www.npmjs.com/package/@quidone/react-native-wheel-picker"> <img src="https://img.shields.io/npm/dw/@quidone/react-native-wheel-picker" alt="Number of downloads per week." /> </a> </p> A flexible React Native Wheel Picker for iOS and Android without using the native side. <table> <tr> <td align="center"> <img src="./docs/images/simple-picker-ios.gif" height="200"/> <br /> On iOS </td> <td align="center"> <img src="./docs/images/simple-picker-android.gif" height="200"/> <br /> On Android </td> <td align="center"> <img src="./docs/images/customized-picker.gif" height="200"/> <br /> Customization </td> </tr> </table> <table> <tr> <td align="center"> <img src="docs/images/date-picker-ios.gif" height="220"/> <br /> DatePicker </td> <td align="center"> <img src="docs/images/picker-control-ios.gif" height="220"/> <br /> PickerControl </td> </tr> </table> ## Features - Without native side. - Unified API. - Only native animations. - [Support native feedback](#Native-Feedback). - [Support virtualization](#withVirtualized). - Compatible with Expo ([Snack][EXPO_SNACK]). - Deep customization - Written ```TypeScript```. ## Installation ```shell yarn add @quidone/react-native-wheel-picker ``` ## Navigation - [Usage](#Usage) - [Native Feedback](#Native-Feedback) - [API](#API) - [WheelPicker](#WheelPicker) - [usePickerItemHeight](#usePickerItemHeight) - [useScrollContentOffset](#useScrollContentOffset) - [withVirtualized](#withVirtualized) - [DatePicker](#DatePicker) - [Picker Control](#Picker-Control) - [usePickerControl](#usePickerControl) - [withPickerControl](#withPickerControl) - [useOnPickerValueChangedEffect](#useOnPickerValueChangedEffect) - [useOnPickerValueChangingEffect](#useOnPickerValueChangingEffect) - [Footer](#-Author) ## Usage ### [🚀 Expo Snack example][EXPO_SNACK] If you want to see more examples and experiment, run the examples locally. ```shell git clone git@github.com:quidone/react-native-wheel-picker.git cd react-native-wheel-picker yarn install cd example && yarn install && yarn ios ``` ### WheelPicker usage ```jsx import React, {useState} from 'react'; import WheelPicker from '@quidone/react-native-wheel-picker'; const data = [...Array(100).keys()].map((index) => ({ value: index, label: index.toString(), })) const App = () => { const [value, setValue] = useState(0); return ( <WheelPicker data={data} value={value} onValueChanged={({item: {value}}) => setValue(value)} enableScrollByTapOnItem={true} /> ); }; export default App; ``` ### DatePicker usage #### Simple case ```tsx import React, {useState} from 'react'; import {DatePicker} from '@quidone/react-native-wheel-picker'; const App = () => { const [date, setDate] = useState('2025-02-02'); return ( <DatePicker date={date} // required format YYYY-MM-DD onDateChanged={({date}) => setDate(date)} /> ); }; ``` #### Customized case You also have a lot of control over each WheelPicker and the rendering process; you can add your own components between individual WheelPickers ```tsx import React, {useState} from 'react'; import {useStableCallback} from '@rozhkov/react-useful-hooks'; import {DatePicker} from '@quidone/react-native-wheel-picker'; const CustomizedDatePicker = () => { const [date, setDate] = useState('2025-02-02'); const onDateChanged = useStableCallback(({date}: {date: string}) => { setDate(date); }); return ( <DatePicker date={date} onDateChanged={onDateChanged} renderDate={() => <DatePicker.Date />} renderMonth={() => <DatePicker.Month />} renderYear={() => <DatePicker.Year />} > {({dateNodes}) => { return dateNodes.map((x) => x.node); }} </DatePicker> ); }; ``` ### PickerControl usage ```tsx import React, {useState} from 'react'; import WheelPicker, { type PickerItem, useOnPickerValueChangedEffect, useOnPickerValueChangingEffect, usePickerControl, withPickerControl, } from '@quidone/react-native-wheel-picker'; import {View} from 'react-native'; const ControlPicker = withPickerControl(WheelPicker); type ControlPickersMap = { value1: {item: PickerItem<number>}; value2: {item: PickerItem<number>}; }; const data = Array.from({length: 100}, (_, index) => ({value: index})); const App = () => { const [value, setValue] = useState({value1: 0, value2: 0}); const pickerControl = usePickerControl<ControlPickersMap>(); useOnPickerValueChangedEffect(pickerControl, (event) => { setValue({ value1: event.pickers.value1.item.value, value2: event.pickers.value2.item.value, }); }); useOnPickerValueChangingEffect(pickerControl, (event) => { // some logic }); return ( <View style={{flexDirection: 'row', justifyContent: 'space-around'}}> <ControlPicker control={pickerControl} pickerName={'value1'} data={data} value={value.value1} width={100} enableScrollByTapOnItem={true} /> <ControlPicker control={pickerControl} pickerName={'value2'} data={data} value={value.value2} width={100} enableScrollByTapOnItem={true} /> </View> ); }; ``` ## Native Feedback You can trigger native sound and impact with [@quidone/react-native-wheel-picker-feedback][FEEDBACK_GITHUB] and onValueChanging event ```jsx // ... import WheelPickerFeedback from '@quidone/react-native-wheel-picker-feedback'; const App = () => { return ( <WheelPicker onValueChanging={() => { WheelPickerFeedback.triggerSoundAndImpact(); }} /> ); }; ``` ## API ### WheelPicker #### Props - ```data``` [array] - items of picker - ```value?``` [any] - current value of picker item - ```itemHeight?``` [number] - height of picker item in the center. - ```visibleItemCount?``` [number] - number of displayed items: 1, 3, 5... (default = 5). For 5, the WheelPicker height is calculated incorrectly, left for backward compatibility. - ```width?``` [number | string] - width of picker. - ```readOnly?``` [boolean] - read only mode. - ```enableScrollByTapOnItem?``` [boolean] - allow scrolling by tap on an item (default = false) - ```extraValues?``` [unknown[]] - external values on which the Picker depends. Can be used as a forced trigger for scroll synchronization, even if it is active - ```testID?``` [string] - Used to locate this component in end-to-end tests. - ```onValueChanging?``` [function] - An event that is triggered when the value is changing. - ```onValueChanged?``` [function] - An event that is triggered when the value is changed (wheel is stopped and no touch). - ```keyExtractor?``` [function] - key extractor from picker item. - ```renderItem?``` [function] - render picker item content. - ```renderItemContainer?``` [function] - render picker item container (there is animated container). - ```renderOverlay?``` [function | null] - render overlay over the picker. - ```renderList?``` [function] - render list (Advanced, It is not recommended to use). - ```style?``` [object | array] - root style. - ```itemTextStyle?``` [object | array] - item text style for picker item. - ```overlayItemStyle?``` [object | array] - style for the overlay element in the center - ```contentContainerStyle?``` [object | array] - style which wraps all of the child views [original](https://reactnative.dev/docs/scrollview#contentcontainerstyle) - ```scrollEventThrottle?``` [object | array] - [original](https://reactnative.dev/docs/scrollview#scrolleventthrottle-ios) - ```disableIntervalMomentum?``` [boolean] - When set to `true`, the scroll view stops on the next snap point relative to the release position instead of carrying through with momentum. Useful as an opt-in workaround for a [react-native bug](https://github.com/facebook/react-native/issues/29922) where some older Android OEM devices (e.g. vivo / Oppo) produce erratic snap behavior. Defaults to React Native's default (off). #### usePickerItemHeight This hook returns the item height which was passed via props. #### useScrollContentOffset This hook returns the animated value of the ScrollView offset. #### withVirtualized This HOC returns virtualized picker ```jsx import WheelPicker, {withVirtualized} from '@quidone/react-native-wheel-picker'; const VirtualizedWheelPicker = withVirtualized(WheelPicker); ``` #### Additional props - ```initialNumToRender?``` (default = ```Math.ceil(visibleItemCount / 2)```) - [original](https://reactnative.dev/docs/flatlist#initialnumtorender). - ```maxToRenderPerBatch?``` (default = ```Math.ceil(visibleItemCount / 2)```) - [original](https://reactnative.dev/docs/flatlist#maxtorenderperbatch). - ```windowSize?``` - [original](https://reactnative.dev/docs/flatlist#windowsize). - ```updateCellsBatchingPeriod?``` (default = 10) - [original](https://reactnative.dev/docs/flatlist#updatecellsbatchingperiod). ### DatePicker A specialized picker component for selecting dates. It supports localization and deep customization. #### Props - ```date``` [string] - Current date in 'YYYY-MM-DD' format - ```onDateChanged``` [function] - Callback fired when date selection is confirmed - ```minDate?``` [string] - Minimum selectable date in 'YYYY-MM-DD' format - ```maxDate?``` [string] - Maximum selectable date in 'YYYY-MM-DD' format - ```locale?``` [string] - Locale for date formatting (default = 'en') - ```renderDate?``` [function] - Custom renderer for date component - ```renderMonth?``` [function] - Custom renderer for month component - ```renderYear?``` [function] - Custom renderer for year component - ```children?``` [function] - Render prop for customizing component layout DatePicker also accepts all the common wheel picker props like `itemHeight`, `visibleItemCount`, `readOnly`, etc. #### Subcomponents DatePicker exposes subcomponents that can be used for custom layouts: - ```DatePicker.Date``` - Day WheelPicker - ```DatePicker.Month``` - Month WheelPicker - ```DatePicker.Year``` - Year WheelPicker ### Picker Control Picker Control provides a way to synchronize multiple WheelPicker components. It is used inside DatePicker. Main goals: 1. Synchronize onValueChanged and onValueChanging events. 2. Synchronize the value selection process. If a value changes, all WheelPickers should accept this value, even if they are still spinning. #### usePickerControl A hook that creates a control object for connecting multiple pickers. See [example](#PickerControl-Usage) #### withPickerControl A HOC that connects a WheelPicker to a control object. See [example](#PickerControl-Usage) ##### Adding props - ```control``` [object] - Control object created with `usePickerControl` - ```pickerName``` [string] - Unique name for the picker within the control group #### useOnPickerValueChangedEffect Called when the value has been changed. This occurs during the inactive state of all WheelPickers. See [example](#PickerControl-Usage) #### useOnPickerValueChangingEffect Called when any of the connected WheelPickers changes. See [example](#PickerControl-Usage) ## 👨‍💻 Author [Sergey Rozhkov][AUTHOR] ## 🎯 Was it helpful? Do you like it and find it helpful? You can help this project in the following way: - ⭐ Put the star. - 💡 Suggest your ideas. - 😉 Open a founded issue. ## 🤝 Contributing See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow. ## 📄 License Quidone React Native Wheel Picker is MIT licensed, as found in the [LICENSE](LICENSE) file. --- Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)