├── .eslintrc.json ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── assets ├── exampleApp-android.gif └── exampleApp.gif ├── example └── ExampleApp │ ├── .buckconfig │ ├── .editorconfig │ ├── .eslintrc.js │ ├── .gitattributes │ ├── .gitignore │ ├── .prettierrc.js │ ├── .watchmanconfig │ ├── App.tsx │ ├── android │ ├── app │ │ ├── _BUCK │ │ ├── build.gradle │ │ ├── build_defs.bzl │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── exampleapp │ │ │ │ └── ReactNativeFlipper.java │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── exampleapp │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle │ ├── app.json │ ├── babel.config.js │ ├── index.js │ ├── ios │ ├── ExampleApp.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── ExampleApp.xcscheme │ ├── ExampleApp.xcworkspace │ │ └── contents.xcworkspacedata │ ├── ExampleApp │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── LaunchScreen.storyboard │ │ └── main.m │ ├── ExampleAppTests │ │ ├── ExampleAppTests.m │ │ └── Info.plist │ ├── Podfile │ └── Podfile.lock │ ├── metro.config.js │ ├── package.json │ ├── tsconfig.json │ └── yarn.lock ├── package.json ├── src ├── components │ ├── AndroidDatePicker.tsx │ ├── AndroidPicker.tsx │ ├── DatePicker.tsx │ ├── DoneBar.tsx │ ├── IOSDatePicker.tsx │ ├── IOSPicker.tsx │ ├── InputButton.tsx │ └── Picker.tsx ├── constants │ ├── animation.ts │ └── item.ts ├── helpers │ ├── animation.ts │ ├── iphone.ts │ └── stylesHelper.ts ├── index.ts └── types │ ├── animation.ts │ ├── datepicker.ts │ ├── doneBar.ts │ ├── index.ts │ ├── input.ts │ └── picker.ts └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "plugins": ["@typescript-eslint"], 5 | "env": { 6 | "es6": true, 7 | "node": true, 8 | "mocha": true 9 | }, 10 | "extends": [ 11 | "eslint:recommended", 12 | "plugin:@typescript-eslint/eslint-recommended", 13 | "plugin:@typescript-eslint/recommended" 14 | ], 15 | "parserOptions": { 16 | "ecmaVersion": 2018, 17 | "sourceType": "module" 18 | }, 19 | "rules": { 20 | "no-console": "off", 21 | "linebreak-style": "off", 22 | "quotes": ["error", "double", { "allowTemplateLiterals": true }], 23 | "keyword-spacing": ["error", { "before": true }], 24 | "space-before-blocks": ["error"], 25 | "@typescript-eslint/ban-ts-comment": "off" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | yarn-error.log 4 | dist/ 5 | .idea 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example 2 | .gitignore 3 | assets 4 | node_modules 5 | src 6 | .eslintrc.json 7 | tsconfig.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 thodubois 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-woodpicker 2 | 3 | Customisable picker and datePicker react-native components for Android and iOS. 4 | 5 | ## Preview 6 | 7 | Preview 8 | Preview-Android 9 | 10 | ## Installation 11 | 12 | ```bash 13 | yarn add react-native-woodpicker @react-native-community/datetimepicker @react-native-picker/picker 14 | ``` 15 | 16 | or 17 | 18 | ```bash 19 | npm install react-native-woodpicker @react-native-community/datetimepicker @react-native-picker/picker --save 20 | ``` 21 | 22 | ### Expo 23 | 24 | ```bash 25 | // add react-native-woodpicker with your package manager (yarn / npm / ...) and : 26 | expo install @react-native-community/datetimepicker @react-native-picker/picker 27 | ``` 28 | 29 | ## Version 30 | 31 | ### 0.1.0 32 | 33 | New Version 0.1.0 integrate new React-Native component **DateTimePicker** from `@react-native-community/datetimepicker` and **Hooks**. 34 | Don't forget to add it to your project. 35 | 36 | ### 0.2.0 37 | 38 | New Version 0.2.0 integrate new React-Native component **Picker** from `@react-native-community/picker`. 39 | 40 | ### 0.3.0 41 | 42 | New Version 0.3.0 use Typescript and change the picker dependency from `@react-native-community/picker` to `@react-native-picker/picker`. 43 | 44 | ## Contribution 45 | 46 | Thanks to everyone for your contribution! 47 | I try my best to review and update this repository. 48 | PR and feedback are welcomed! 49 | 50 | ## Usage 51 | 52 | ### Picker 53 | 54 | You can use Picker to pick values/objects. 55 | 56 | ```jsx 57 | import type { PickerItem } from 'react-native-woodpicker' 58 | import { Picker } from 'react-native-woodpicker' 59 | 60 | [...] 61 | 62 | const ExampleApp = (): JSX.Element => { 63 | const [pickedData, setPickedData] = useState(); 64 | 65 | const data: Array = [ 66 | { label: "DataCat", value: 1 }, 67 | { label: "DataDog", value: 2 }, 68 | { label: "DataSnake", value: 3 }, 69 | { label: "DataPlatypus", value: 4 }, 70 | { label: "DataWhale", value: 5 } 71 | ]; 72 | 73 | return ( 74 | 75 | 87 | 88 | ); 89 | } 90 | ``` 91 | 92 | ### DatePicker 93 | 94 | You can use DatePicker to pick Dates. 95 | Unlike the Picker, you need to handle the placeholder. 96 | 97 | ```jsx 98 | import { DatePicker } from 'react-native-woodpicker' 99 | 100 | [...] 101 | 102 | const ExampleApp = (): JSX.Element => { 103 | const [pickedDate, setPickedDate] = useState(); 104 | 105 | const handleText = (): string => pickedDate 106 | ? pickedDate.toDateString() 107 | : "No value Selected"; 108 | 109 | return ( 110 | 111 | 127 | 128 | ); 129 | } 130 | ``` 131 | 132 | ## Props 133 | 134 | ### General 135 | 136 | | Name | type | Required | Description | 137 | | ---------------------- | ------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------ | 138 | | **title** | string | false | Change DoneBar title | 139 | | **doneButtonLabel** | string | false | Change done button label | 140 | | **style** | ViewStyle | false | Configure the input style (View) | 141 | | **containerStyle** | ViewStyle | false | Configure the input container style (View) | 142 | | **textInputStyle** | TextStyle | false | Configure the input text style (Text) | 143 | | **disabled** | boolean | false | Disable the input | 144 | | **isNullable** | boolean | false | Picker : Add null value on items, DatePicker: add reset button | 145 | | **InputComponent** | React.ElementType | false | Component to replace input. | 146 | | **DoneBarComponent** | React.ElementType | false | Component to replace iOS Picker Done Bar | 147 | | **onOpen** | function | false | Triggered when the picker is opening | 148 | | **onClose** | function | false | Triggered when the picker is closing | 149 | | **backdropAnimation** | Object | false | Configure backdrop animation property. Default: {opacity: 0.5 , duration: 1000, delay: 300} | 150 | | **iOSCustomProps** | Object | false | Configure iOS props to pass to the native component (Picker or DatePicker) from `react-native-community` | 151 | | **androidCustomProps** | Object | false | Configure Android props to pass to the native component (Picker or DatePicker) from `react-native-community` | 152 | 153 | ### Picker 154 | 155 | | Name | type | Required | Description | 156 | | ----------------------- | ------------------------------------------ | -------- | ---------------------------------------------------------------------------------------- | 157 | | **item** | PickerItem ({ label: string, value: any }) | true | Configure the current selected item | 158 | | **placeholder** | string | false | Configure the picker label if no item is selected | 159 | | **onItemChange** | (item: PickerItem, index: number) => void; | true | Add listener on change event | 160 | | **items** | Array | true | Configure the list of available items | 161 | | **mode** (Android Only) | "dialog" or "dropdown" | false | Configure the android picker mode | 162 | | **itemFontFamily** | string | false | Configure the default font family for items (each item can have a `fontFamily` property) | 163 | | **itemColor** | string | false | Configure the default color for items (each item can have a `color` property) | 164 | 165 | ### DatePicker 166 | 167 | | Name | type | Required | Description | 168 | | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------- | 169 | | **value** | Date | true | Configure the picker title (not the placeholder) | 170 | | **onDateChange** | (date: ?Date) => {} | true | Configure the placeholder when no value is selected | 171 | | **locale** | string ([Locale IDs](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html)) | false | Change the iOS picker locale | 172 | | **iosMode** (iOS Only) | "date" or "time" or "datetime" | false | Change the iOS picker mode | 173 | | **androidMode** (Android Only) | "calendar" or "spinner" or "default" | false | Change the Android picker mode | 174 | | **iosDisplay** (iOS Only) | "default" or "spinner" or "inline" or "compact" | false | Change the iOS picker display | 175 | | **androidDisplay** (Android Only) | "default" or "spinner" or "calendar" or "clock" | false | Change the Android picker display | 176 | | **minimumDate** | Date | false | Restrict date selection with a minimum date | 177 | | **maximumDate** | Date | false | Restrict date selection with a minimum date | 178 | | **neutralButtonLabel** (Android Only) | string | false | Change "clear" button label | 179 | | **is24Hour** (Android Only) | boolean | false | Changing timepicker to 24h format | 180 | | **textColor** (iOS Only) | string | false | Change text color on "spinner" display | 181 | | **text** | string | false | Change picker button text | 182 | | **onOpen** | () => void | false | Add listener on modal open event | 183 | | **onClose** | () => void | false | Add listener on modal close event | 184 | | **minuteInterval** | number : 1 or 2 or 3 or 4 or 5 or 6 or 10 or 12 or 15 or 20 or 30 | false | The interval at which minutes can be selected | 185 | | **timeZoneOffsetInMinutes** | number | false | Change the timeZone of the date picker | 186 | | **iosCompactHiddenStyle** (iOS only) | ViewStyle | false | Change style for the ios picker in compact mode | 187 | | **touchableStyle** | ViewStyle | false | Change style touchable view in the picker | 188 | 189 | ### ItemComponent specific 190 | 191 | | Name | type | Description | 192 | | ------------------------------------------- | -------------------------------------- | ----------------------------------------------------------------------- | 193 | | **resetValue** | () => void | Reset value to null if nullable (DatePicker only) | 194 | | **togglePicker** | (event: GestureResponderEvent) => void | Close Picker (iOS only) | 195 | | **text** | string | Input text recieved from the current element | 196 | | **textInputStyle** | StyleObj | textInputStyle props configured in the picker component | 197 | | **isNullable** | boolean | isNullable props configured in the picker component | 198 | | **isCompactHiddenPickerNeeded** (iOS only) | boolean | `true` if you need to use `renderHiddenCompactIOSPicker` | 199 | | **renderHiddenCompactIOSPicker** (iOS only) | () => JSX.Element | Render the DateTimePicker as a invisible button that overlay his parent | 200 | 201 | ### DoneBar Picker specific (iOS only) 202 | 203 | | Name | type | Description | 204 | | ------------------- | -------------------------------------- | -------------------------------------------------------- | 205 | | **title** | string | title props configured in the picker component | 206 | | **doneButtonLabel** | string | doneButtonLabel props configured in the picker component | 207 | | **onDonePress** | (event: GestureResponderEvent) => void | Close the picker and trigger onChange | 208 | -------------------------------------------------------------------------------- /assets/exampleApp-android.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thodubois/react-native-woodpicker/9a9603e7ece24b51a201cfbb1a2791e0fe6809e9/assets/exampleApp-android.gif -------------------------------------------------------------------------------- /assets/exampleApp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thodubois/react-native-woodpicker/9a9603e7ece24b51a201cfbb1a2791e0fe6809e9/assets/exampleApp.gif -------------------------------------------------------------------------------- /example/ExampleApp/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /example/ExampleApp/.editorconfig: -------------------------------------------------------------------------------- 1 | # Windows files 2 | [*.bat] 3 | end_of_line = crlf 4 | -------------------------------------------------------------------------------- /example/ExampleApp/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native-community', 4 | }; 5 | -------------------------------------------------------------------------------- /example/ExampleApp/.gitattributes: -------------------------------------------------------------------------------- 1 | # Windows files should use crlf line endings 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | *.bat text eol=crlf 4 | -------------------------------------------------------------------------------- /example/ExampleApp/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | 24 | # Android/IntelliJ 25 | # 26 | build/ 27 | .idea 28 | .gradle 29 | local.properties 30 | *.iml 31 | *.hprof 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | !debug.keystore 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://docs.fastlane.tools/best-practices/source-control/ 51 | 52 | */fastlane/report.xml 53 | */fastlane/Preview.html 54 | */fastlane/screenshots 55 | 56 | # Bundle artifact 57 | *.jsbundle 58 | 59 | # CocoaPods 60 | /ios/Pods/ 61 | -------------------------------------------------------------------------------- /example/ExampleApp/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: false, 3 | jsxBracketSameLine: true, 4 | singleQuote: true, 5 | trailingComma: 'all', 6 | arrowParens: 'avoid', 7 | }; 8 | -------------------------------------------------------------------------------- /example/ExampleApp/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/ExampleApp/App.tsx: -------------------------------------------------------------------------------- 1 | import type {PickerItem} from 'react-native-woodpicker'; 2 | 3 | import React, {useState} from 'react'; 4 | import {Platform, StyleSheet, Text, View, Button} from 'react-native'; 5 | 6 | import { 7 | DatePicker, 8 | Picker, 9 | PickerInstance, 10 | DatePickerInstance, 11 | } from 'react-native-woodpicker'; 12 | 13 | const data: Array = [ 14 | {label: 'DataCat', value: 1}, 15 | {label: 'DataDog', value: 2}, 16 | {label: 'DataSnake', value: 3}, 17 | {label: 'DataPlatypus', value: 4}, 18 | {label: 'DataWhale', value: 5}, 19 | ]; 20 | 21 | const App = (): JSX.Element => { 22 | const [pickedDate, setPickedDate] = useState(null); 23 | const [pickedData, setPickedData] = useState(); 24 | 25 | const pickerRef = React.useRef(null); 26 | const datePickerRef = React.useRef(null); 27 | const handleDateChange = (date: Date | null) => setPickedDate(date); 28 | 29 | const resetDate = () => setPickedDate(new Date()); 30 | const resetPicker = () => setPickedData(data[1]); 31 | 32 | const instructions = Platform.select({ 33 | ios: 'Welcome to the iOS Example App for react-native-woodpicker. Enjoy!', 34 | android: 35 | 'Welcome to the Android Example App for react-native-woodpicker. Enjoy!', 36 | }); 37 | 38 | const handleText = () => pickedDate?.toDateString?.() ?? 'No value Selected'; 39 | const openPickerWidthRef = () => pickerRef.current?.open(); 40 | const openDatePickerWithRef = () => datePickerRef.current?.open(); 41 | 42 | return ( 43 | 44 | Welcome to React Native! 45 | To get started, edit App.js 46 | {instructions} 47 | 58 |