├── LICENSE ├── PDP.js ├── README.md ├── index.js ├── modules └── index.js ├── package.json └── yarn.lock /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /PDP.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from "react"; 3 | import { View, Keyboard } from "react-native"; 4 | import moment from "moment-jalaali"; 5 | import Picker from "react-native-picker"; 6 | import { toFaDigit, convertNumberToEnglish } from "./modules"; 7 | import { primaryFontFamily, smallFont } from "./modules"; 8 | 9 | type Props = { 10 | type: "Jalali" | "Gregorian", 11 | pickerConfirmBtnText: string, 12 | pickerTitleText: string, 13 | pickerCancelBtnColor: [number, number, number, number], 14 | pickerToolBarFontSize: number, 15 | pickerFontSize: number, 16 | pickerToolBarBg: [number, number, number, number], 17 | pickerConfirmBtnColor: [number, number, number, number], 18 | pickerTitleColor: [number, number, number, number], 19 | pickerBg: [number, number, number, number], 20 | pickerCancelBtnText: string, 21 | yearCount: number, 22 | onConfirm: () => moment.Moment, 23 | onPickerCancel: Function, 24 | onSelect: Function, 25 | pickerFontFamily: string 26 | }; 27 | 28 | export default class PheebsDatePicker extends Component { 29 | static defaultProps = { 30 | pickerCancelBtnText: "لغو", 31 | pickerTitleText: "تاریخ را انتخاب کنید", 32 | pickerConfirmBtnText: "انتخاب", 33 | onConfirm: date => console.warn(date), 34 | pickerCancelBtnColor: [0, 0, 0, 1], 35 | pickerFontSize: 18, 36 | pickerToolBarBg: [232, 232, 232, 1], 37 | pickerConfirmBtnColor: [0, 0, 0, 1], 38 | pickerTitleColor: [0, 0, 0, 1], 39 | pickerBg: [255, 255, 255, 255], 40 | pickerToolBarFontSize: smallFont 41 | }; 42 | hidePicker() { 43 | this.pickerIsOpen = false; 44 | Picker.hide(); 45 | } 46 | isOpen() { 47 | return this.pickerIsOpen; 48 | } 49 | showPicker = () => { 50 | const { 51 | pickerCancelBtnText, 52 | pickerTitleText, 53 | pickerConfirmBtnText, 54 | onConfirm, 55 | pickerCancelBtnColor, 56 | pickerToolBarFontSize, 57 | onPickerCancel, 58 | pickerFontSize, 59 | pickerToolBarBg, 60 | pickerConfirmBtnColor, 61 | pickerTitleColor, 62 | pickerFontFamily, 63 | pickerBg 64 | } = this.props; 65 | Picker.init({ 66 | pickerCancelBtnText, 67 | pickerTitleText, 68 | pickerCancelBtnColor, 69 | pickerToolBarFontSize, 70 | pickerFontSize, 71 | pickerToolBarBg, 72 | pickerConfirmBtnColor, 73 | pickerFontFamily, 74 | pickerTitleColor, 75 | pickerBg, 76 | pickerConfirmBtnText, 77 | pickerTextEllipsisLen: 100, 78 | pickerData: this.data, 79 | selectedValue : this.defaultValue(), 80 | onPickerConfirm: data => { 81 | this.props.type === "Gregorian" 82 | ? this.gregorianConfirm(data) 83 | : this.jalaliConfirm(data); 84 | }, 85 | onPickerCancel: data => { 86 | this.pickerIsOpen = false; 87 | if (onPickerCancel) { 88 | onPickerCancel(); 89 | } 90 | }, 91 | onPickerSelect: data => { 92 | let [year, month, day] = data; 93 | 94 | if (this.oldYear && year !== this.oldYear) { 95 | month = this.oldMonth; 96 | day = this.oldDay; 97 | } else if (this.oldMonth && month !== this.oldMonth) { 98 | day = this.oldDay; 99 | } 100 | 101 | this.oldYear = year 102 | this.oldMonth = month 103 | this.oldDay = day 104 | 105 | Picker.select([year, month, day]) 106 | } 107 | }); 108 | Keyboard.dismiss(); 109 | Picker.show(); 110 | this.pickerIsOpen = true; 111 | }; 112 | gregorianConfirm(data) { 113 | const { onConfirm } = this.props; 114 | data[1] = this.getMonthNumberEng(data[1]); 115 | data[0] = convertNumberToEnglish(data[0]); 116 | data[2] = convertNumberToEnglish(data[2]); 117 | this.setState({ year: data[0], day: data[2], month: data[1] }); 118 | m = new moment(data[0] + "/" + data[1] + "/" + data[2], "'YYYY/M/D'"); 119 | onConfirm(m); 120 | this.pickerIsOpen = false; 121 | } 122 | jalaliConfirm(data) { 123 | const { onConfirm } = this.props; 124 | data[1] = this.getMonthNumber(data[1]); 125 | data[0] = convertNumberToEnglish(data[0]); 126 | data[2] = convertNumberToEnglish(data[2]); 127 | this.setState({ year: data[0], day: data[2], month: data[1] }); 128 | m = new moment(data[0] + "/" + data[1] + "/" + data[2], "'jYYYY/jM/jD'"); 129 | onConfirm(m); 130 | this.pickerIsOpen = false; 131 | } 132 | render() { 133 | this.data = 134 | this.props.type === "Gregorian" 135 | ? this._createGregorianDates() 136 | : this._createDates(); 137 | return ( 138 | 139 | ); 140 | } 141 | 142 | defaultValue = () => { 143 | const {defaultValue} = this.props 144 | if (defaultValue) { 145 | const value = this.props.type === "Gregorian" 146 | ? this._gregorianDefaultValue() 147 | : this._defaultValue(); 148 | 149 | console.log('value',value); 150 | 151 | return value; 152 | } 153 | 154 | return undefined; 155 | } 156 | 157 | _gregorianDefaultValue = () => { 158 | const {defaultValue} = this.props 159 | const m = moment(defaultValue, "YYYY/M/D"); 160 | 161 | this.oldYear = m.year() + ''; 162 | this.oldMonth = this.getMonthStringEng(m.month() + 1); 163 | this.oldDay = m.date() + ''; 164 | 165 | return [ 166 | this.oldYear, 167 | this.oldMonth, 168 | this.oldDay 169 | ] 170 | } 171 | 172 | _defaultValue = () => { 173 | const {defaultValue} = this.props 174 | const m = moment(defaultValue, "jYYYY/jM/jD"); 175 | 176 | this.oldYear = toFaDigit(m.jYear()) + ''; 177 | this.oldMonth = this.getMonthString(m.jMonth() + 1); 178 | this.oldDay = toFaDigit(m.jDate()); 179 | 180 | return [ 181 | this.oldYear, 182 | this.oldMonth, 183 | this.oldDay 184 | ] 185 | } 186 | 187 | _createDates() { 188 | var MaxMonth; 189 | var MaxYear; 190 | var MaxDay; 191 | if (this.props.maxDate == undefined) { 192 | maxDate = moment(); 193 | maxDate.add(this.props.yearCount, "jYear"); 194 | var MaxYear = maxDate.jYear(); 195 | var MaxMonth = 12; 196 | if (moment.jIsLeapYear(_year)) { 197 | var MaxDay = 30; 198 | } else { 199 | var MaxDay = 29; 200 | } 201 | } else { 202 | m = moment(this.props.maxDate, "jYYYY/jM/jD"); 203 | var MaxMonth = m.jMonth(); 204 | var MaxYear = m.jYear(); 205 | var MaxDay = m.jDate(); 206 | } 207 | m = 208 | this.props.minDate == undefined 209 | ? moment() 210 | : moment(this.props.minDate, "jYYYY/jM/jD"); 211 | var month = m.jMonth(); 212 | var year = m.jYear(); 213 | var day = m.jDate(); 214 | 215 | let data = []; 216 | 217 | for (let i = 0; m.jYear() <= MaxYear; i++) { 218 | var _year = m.jYear(); 219 | let months = []; 220 | for (let j = 0; j < 12; j++) { 221 | var daysLength = moment.jIsLeapYear(_year) ? 30 : 29; 222 | if (j != 11) { 223 | daysLength = 30; 224 | } 225 | if (j <= 5) { 226 | daysLength = 31; 227 | } 228 | if (_year == MaxYear && j > MaxMonth) break; 229 | if (year == _year && j < month) continue; 230 | let days = []; 231 | for (let k = 0; k < daysLength; k++) { 232 | if (_year == MaxYear && j == MaxMonth && k == MaxDay) break; 233 | if (_year == year && month == j && k < day - 1) continue; 234 | days.push(toFaDigit(k + 1)); 235 | } 236 | let _days = {}; 237 | _days[this.getMonthString(j + 1)] = days; 238 | months.push(_days); 239 | } 240 | let _data = {}; 241 | _data[toFaDigit(_year)] = months; 242 | data.push(_data); 243 | m.add(1, "jYear"); 244 | } 245 | return data; 246 | } 247 | getMonthString(number) { 248 | switch (number) { 249 | case 1: 250 | return "فروردین"; 251 | case 2: 252 | return "اردیبهشت"; 253 | case 3: 254 | return "خرداد"; 255 | case 4: 256 | return "تیر"; 257 | case 5: 258 | return "مرداد"; 259 | case 6: 260 | return "شهریور"; 261 | case 7: 262 | return "مهر"; 263 | case 8: 264 | return "آبان"; 265 | case 9: 266 | return "آذر"; 267 | case 10: 268 | return "دی"; 269 | case 11: 270 | return "بهمن"; 271 | case 12: 272 | return "اسفند"; 273 | } 274 | return number; 275 | } 276 | getMonthNumber(string) { 277 | switch (string) { 278 | case "فروردین": 279 | return 1; 280 | case "اردیبهشت": 281 | return 2; 282 | case "خرداد": 283 | return 3; 284 | case "تیر": 285 | return 4; 286 | case "مرداد": 287 | return 5; 288 | case "شهریور": 289 | return 6; 290 | case "مهر": 291 | return 7; 292 | case "آبان": 293 | return 8; 294 | case "آذر": 295 | return 9; 296 | case "دی": 297 | return 10; 298 | case "بهمن": 299 | return 11; 300 | case "اسفند": 301 | return 12; 302 | } 303 | return 0; 304 | } 305 | 306 | _createGregorianDates() { 307 | var MaxMonth; 308 | var MaxYear; 309 | var MaxDay; 310 | if (this.props.maxDate == undefined) { 311 | maxDate = moment(); 312 | maxDate.add(this.props.yearCount, "Year"); 313 | var MaxYear = maxDate.year(); 314 | var MaxMonth = 12; 315 | var MaxDay = 31; 316 | } else { 317 | m = moment(this.props.maxDate, "YYYY/M/D"); 318 | var MaxMonth = m.month(); 319 | var MaxYear = m.year(); 320 | var MaxDay = m.date(); 321 | } 322 | m = 323 | this.props.minDate == undefined 324 | ? moment() 325 | : moment(this.props.minDate, "YYYY/M/D"); 326 | var month = m.month(); 327 | var year = m.year(); 328 | var day = m.date(); 329 | let data = []; 330 | for (let i = 0; m.year() <= MaxYear; i++) { 331 | var _year = m.year(); 332 | let months = []; 333 | for (let j = 0; j < 12; j++) { 334 | if (j == 1) { 335 | if (moment(_year + "/" + (j + 1) + "/29", "YYYY/M/DD").isValid()) { 336 | daysLength = 29; 337 | } else { 338 | daysLength = 28; 339 | } 340 | } else if ( 341 | moment(_year + "/" + (j + 1) + "/31", "YYYY/M/DD").isValid() 342 | ) { 343 | daysLength = 31; 344 | } else { 345 | daysLength = 30; 346 | } 347 | if (_year == MaxYear && j > MaxMonth) break; 348 | if (year == _year && j < month) continue; 349 | let days = []; 350 | for (let k = 0; k < daysLength; k++) { 351 | if (_year == MaxYear && j == MaxMonth && k == MaxDay) break; 352 | if (_year == year && month == j && k < day - 1) continue; 353 | days.push(k + 1); 354 | } 355 | let _days = {}; 356 | _days[this.getMonthStringEng(j + 1)] = days; 357 | months.push(_days); 358 | } 359 | let _data = {}; 360 | _data[_year] = months; 361 | data.push(_data); 362 | m.add(1, "year"); 363 | } 364 | return data; 365 | } 366 | getMonthStringEng(number) { 367 | switch (number) { 368 | case 1: 369 | return "January"; 370 | case 2: 371 | return "February"; 372 | case 3: 373 | return "March"; 374 | case 4: 375 | return "April"; 376 | case 5: 377 | return "May"; 378 | case 6: 379 | return "June"; 380 | case 7: 381 | return "July"; 382 | case 8: 383 | return "August"; 384 | case 9: 385 | return "September"; 386 | case 10: 387 | return "October"; 388 | case 11: 389 | return "November"; 390 | case 12: 391 | return "December"; 392 | } 393 | return number; 394 | } 395 | getMonthNumberEng(string) { 396 | switch (string) { 397 | case "January": 398 | return 1; 399 | case "February": 400 | return 2; 401 | case "March": 402 | return 3; 403 | case "April": 404 | return 4; 405 | case "May": 406 | return 5; 407 | case "June": 408 | return 6; 409 | case "July": 410 | return 7; 411 | case "August": 412 | return 8; 413 | case "September": 414 | return 9; 415 | case "October": 416 | return 10; 417 | case "November": 418 | return 11; 419 | case "December": 420 | return 12; 421 | } 422 | return number; 423 | } 424 | } 425 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rn-persian-date-picker 2 | 3 | a simple persian date picker for react native 4 | 5 | # ScreenShots : 6 | 7 | 8 | 9 | . 10 | 11 | 12 | 13 | # Installing: 14 | 15 | # Step 1: 16 | 17 | npm i rn-persian-date-picker --save 18 | 19 | ## OR 20 | yarn add rn-persian-date-picker 21 | 22 | # Step 2: 23 | 24 | react-native link react-native-picker 25 | 26 | # Usage 27 | 28 | ```javascript 29 | import PersianDatePicker from "rn-persian-date-picker"; 30 | export default class App extends Component { 31 | render() { 32 | return ( 33 | 41 | this.picker.showPicker()}> 42 | 43 | 44 | {selectedDate.format("jYYYY/jMM/jDD")} //for more formats and functions go to moment-jalaali 45 | 46 | 47 | 48 | this.setState({ selectedDate: date })} 52 | ref={ref => (this.picker = ref)} 53 | /> 54 | 55 | ); 56 | } 57 | } 58 | ``` 59 | 60 | # props 61 | 62 | | prop | desc | example | 63 | | --------------------- | :--------------------------------------------------------------------------------------------------------: | ---------------------: | 64 | | type | type of date picker( can be "Gregorian" or "Jalali" ) | | 65 | | yearCount | count of years to be show from now | 10 | 66 | | pickerConfirmBtnText | text of confirm Button | "انتخاب" | 67 | | pickerTitleText | title of picker | "تاریخ را انتخاب کنید" | 68 | | pickerCancelBtnText | text of cancel Button | "لغو" | 69 | | pickerCancelBtnColor | color of cancel button ( RGBA array ) | [0, 0, 0, 1] | 70 | | pickerToolBarBg | tollbar background color ( RGBA array ) | [0, 0, 0, 1] | 71 | | pickerConfirmBtnColor | color of confirm button ( RGBA array ) | [0, 0, 0, 1] | 72 | | pickerTitleColor | title color ( RGBA array ) | [0, 0, 0, 1] | 73 | | pickerBg | picker background color ( RGBA array ) | [0, 0, 0, 1] | 74 | | pickerFontFamily | font family of the picker items | | 75 | | minDate | picker start date (string, can be jalali( 1398/08/08 ) or gregorian( 2019/09/09 ) ) | | 76 | | maxDate | picker max date(string, just like minDate, can be use instead of yearCount and) | | 77 | | onConfirm | function that be called when a date select(argument that pass to onConfirm is a Moment-jalali date object) | (date:moment-jalaali) | 78 | | onPickerCancel | function that be called when a user press the cancel button | | 79 | 80 | # methods 81 | 82 | | method | desc | example | 83 | | ---------- | :------------------------------------------------------------------------: | ------: | 84 | | showPicker | open the date picker | | 85 | | hidePicker | close the date picker | | 86 | | isOpen | return date picker status (true : picker is open, false : picker is close) | | 87 | 88 | # Example 89 | 90 | ```javascript 91 | import React, { Component } from "react"; 92 | import { Text, View } from "react-native"; 93 | import PersianDatePicker from "rn-persian-date-picker"; 94 | 95 | export default class App extends Component { 96 | render() { 97 | return ( 98 | 106 | this.picker.showPicker()}> 107 | 108 | 109 | {selectedDate.format("jYYYY/jMM/jDD")} //for more formats and 110 | functions go to moment Jalali 111 | 112 | 113 | 114 | this.setState({ selectedDate: date })} 118 | ref={ref => (this.picker = ref)} 119 | /> 120 | 121 | ); 122 | } 123 | } 124 | ``` 125 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import PersianDatePicker from "./PDP"; 2 | 3 | export default PersianDatePicker; 4 | -------------------------------------------------------------------------------- /modules/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export const toFaDigit = (input: string = "0"): string => { 3 | return input != null 4 | ? ("" + input).replace( 5 | /\d+/g, 6 | (digit: string): string => { 7 | let ret = ""; 8 | for (let i = 0, len = digit.length; i < len; i += 1) { 9 | ret += String.fromCharCode(digit.charCodeAt(i) + 1728); 10 | } 11 | return ret; 12 | } 13 | ) 14 | : ""; 15 | }; 16 | export const convertNumberToEnglish = input => { 17 | if (!input) { 18 | return ""; 19 | } 20 | let ret = ""; 21 | for (let i = 0; i < input.length; i += 1) { 22 | ret += FaEnDigit[input[i]] || ArEnDigit[input[i]] || input[i]; 23 | } 24 | return ret; 25 | }; 26 | 27 | import { Platform, PixelRatio } from "react-native"; 28 | 29 | export const veryVerySmallFont = normalize(10); 30 | export const verySmallFont = normalize(12); 31 | export const smallFont = normalize(14); 32 | export const mediumFont = normalize(16); 33 | export const largFont = normalize(18); 34 | export const xlargFont = normalize(22); 35 | export const xxlargFont = normalize(25); 36 | export const xxxlargFont = normalize(28); 37 | export const veryLargFont = normalize(30); 38 | export const ultraLarge = normalize(32); 39 | export const xUltraLarge = normalize(35); 40 | export const xxUltraLarge = normalize(40); 41 | export const xxxUltraLarge = normalize(48); 42 | export const primaryFontFamily = "IRANSans"; 43 | export const secondaryFontFamily = "IRANSans"; 44 | export const weightUltraLight = "UltraLight"; 45 | export const weightLight = "Light"; 46 | export const weightMedium = "Medium"; 47 | export const weightBold = "Bold"; 48 | 49 | export function normalize(size: number): number { 50 | if (Platform.OS === "ios") { 51 | return Math.round(PixelRatio.roundToNearestPixel(size)); 52 | } 53 | return Math.round(PixelRatio.roundToNearestPixel(size)) - 2; 54 | } 55 | 56 | const fontWeights = { 57 | Black: "900", 58 | Bold: "700", 59 | Medium: "400", 60 | Light: "300", 61 | UltraLight: "100" 62 | }; 63 | 64 | type fontWeightType = 65 | | "normal" 66 | | "bold" 67 | | "100" 68 | | "200" 69 | | "300" 70 | | "400" 71 | | "500" 72 | | "600" 73 | | "700" 74 | | "800" 75 | | "900"; 76 | 77 | export const fontMaker = ( 78 | fontFamily: string, 79 | weight: string 80 | ): { 81 | fontFamily: string, 82 | fontWeight?: fontWeightType 83 | } => { 84 | if (Platform.OS === "android") { 85 | if (fontFamily === "IRANSans") { 86 | return { 87 | fontFamily: 88 | weight === weightMedium ? `${fontFamily}` : `${fontFamily}_${weight}` 89 | }; 90 | } 91 | return { 92 | fontFamily: 93 | weight === weightMedium ? fontFamily : `${fontFamily}_${weight}` 94 | }; 95 | } 96 | const outWeight = fontWeights[weight]; 97 | return { 98 | fontFamily, 99 | fontWeight: outWeight 100 | }; 101 | }; 102 | const ArEnDigit = { 103 | "٠": "0", 104 | "١": "1", 105 | "٢": "2", 106 | "٣": "3", 107 | "٤": "4", 108 | "٥": "5", 109 | "٦": "6", 110 | "٧": "7", 111 | "٨": "8", 112 | "٩": "9" 113 | }; 114 | const FaEnDigit = { 115 | "۰": "0", 116 | "۱": "1", 117 | "۲": "2", 118 | "۳": "3", 119 | "۴": "4", 120 | "۵": "5", 121 | "۶": "6", 122 | "۷": "7", 123 | "۸": "8", 124 | "۹": "9" 125 | }; 126 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rn-persian-date-picker", 3 | "version": "1.0.5", 4 | "description": "a simple date picker for Jalali and Gregorian", 5 | "main": "index.js", 6 | "private": false, 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [ 11 | "react-native", 12 | "date picker", 13 | "persian date picker", 14 | "jalali date picker", 15 | "picker" 16 | ], 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/mldb/rn-persian-date-picker.git" 20 | }, 21 | "author": "mldb", 22 | "license": "Apache", 23 | "dependencies": { 24 | "moment-jalaali": "^0.8.3", 25 | "react-native-picker": "^4.3.7" 26 | }, 27 | "peerDependencies": { 28 | "react-native": "^0.41.2", 29 | "react-native-windows": "0.41.0-rc.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | balanced-match@^1.0.0: 6 | version "1.0.0" 7 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 8 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 9 | 10 | brace-expansion@^1.1.7: 11 | version "1.1.11" 12 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 13 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 14 | dependencies: 15 | balanced-match "^1.0.0" 16 | concat-map "0.0.1" 17 | 18 | concat-map@0.0.1: 19 | version "0.0.1" 20 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 21 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 22 | 23 | fs.realpath@^1.0.0: 24 | version "1.0.0" 25 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 26 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 27 | 28 | glob@^7.1.3: 29 | version "7.1.4" 30 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" 31 | integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== 32 | dependencies: 33 | fs.realpath "^1.0.0" 34 | inflight "^1.0.4" 35 | inherits "2" 36 | minimatch "^3.0.4" 37 | once "^1.3.0" 38 | path-is-absolute "^1.0.0" 39 | 40 | inflight@^1.0.4: 41 | version "1.0.6" 42 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 43 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 44 | dependencies: 45 | once "^1.3.0" 46 | wrappy "1" 47 | 48 | inherits@2: 49 | version "2.0.3" 50 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 51 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 52 | 53 | jalaali-js@^1.1.0: 54 | version "1.1.0" 55 | resolved "https://registry.yarnpkg.com/jalaali-js/-/jalaali-js-1.1.0.tgz#f0e942049273d11f7298a992356fc36ce2784863" 56 | integrity sha512-eznOFGRtHb0ttHkHf8pVYPVfKJdbOqutTwcQYACbv91Q2NiYgnM5Z6+NN/8FMAhuMDAXAmeAG9+UBzqVKdA4cg== 57 | 58 | minimatch@^3.0.4: 59 | version "3.0.4" 60 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 61 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 62 | dependencies: 63 | brace-expansion "^1.1.7" 64 | 65 | moment-jalaali@^0.8.3: 66 | version "0.8.3" 67 | resolved "https://registry.yarnpkg.com/moment-jalaali/-/moment-jalaali-0.8.3.tgz#93d5de9c274be0221fabd3c3f2b7efc3c51e9016" 68 | integrity sha512-FjFjbqHnm9JB5AbcBqPtJ82I1WgjUupbjhKhd513ZkWBcbyQuq0IcEPYSdZ7EMgCYFFrE/W24vs1C2IpSqWuyg== 69 | dependencies: 70 | jalaali-js "^1.1.0" 71 | moment "^2.22.2" 72 | moment-timezone "^0.5.21" 73 | rimraf "^2.6.2" 74 | 75 | moment-timezone@^0.5.21: 76 | version "0.5.25" 77 | resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.25.tgz#a11bfa2f74e088327f2cd4c08b3e7bdf55957810" 78 | integrity sha512-DgEaTyN/z0HFaVcVbSyVCUU6HeFdnNC3vE4c9cgu2dgMTvjBUBdBzWfasTBmAW45u5OIMeCJtU8yNjM22DHucw== 79 | dependencies: 80 | moment ">= 2.9.0" 81 | 82 | "moment@>= 2.9.0", moment@^2.22.2: 83 | version "2.24.0" 84 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" 85 | integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== 86 | 87 | once@^1.3.0: 88 | version "1.4.0" 89 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 90 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 91 | dependencies: 92 | wrappy "1" 93 | 94 | path-is-absolute@^1.0.0: 95 | version "1.0.1" 96 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 97 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 98 | 99 | react-native-picker@^4.3.7: 100 | version "4.3.7" 101 | resolved "https://registry.yarnpkg.com/react-native-picker/-/react-native-picker-4.3.7.tgz#9842e8c62ff0d8b676e9514d9f9172413c0518a8" 102 | integrity sha1-mELoxi/w2LZ26VFNn5FyQTwFGKg= 103 | 104 | rimraf@^2.6.2: 105 | version "2.6.3" 106 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" 107 | integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== 108 | dependencies: 109 | glob "^7.1.3" 110 | 111 | rn-persian-date-picker@^1.0.1: 112 | version "1.0.1" 113 | resolved "https://registry.yarnpkg.com/rn-persian-date-picker/-/rn-persian-date-picker-1.0.1.tgz#4462c2e1292946adb798cb9be71fbdc1d3b5b1df" 114 | integrity sha512-8l/agZ8mQ2WWOU7+fmio7PsSSkBlHM5wSeqy3UW4QV3i61UyiduMT+Q654kteJeFIMBEv0dcYfGu7HHSo968CA== 115 | dependencies: 116 | moment-jalaali "^0.8.3" 117 | react-native-picker "^4.3.7" 118 | 119 | wrappy@1: 120 | version "1.0.2" 121 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 122 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 123 | --------------------------------------------------------------------------------