├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── android ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── chymtt │ │ └── reactnativecalendar │ │ ├── Calendar.java │ │ ├── CalendarEvent.java │ │ ├── CalendarManager.java │ │ └── CalendarPackage.java │ └── res │ └── values │ └── styles.xml ├── package.json └── src └── Calendar.js /.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 | project.xcworkspace 24 | 25 | # Android/IJ 26 | # 27 | .idea 28 | .gradle 29 | local.properties 30 | 31 | # node.js 32 | # 33 | node_modules/ 34 | npm-debug.log 35 | 36 | *.iml -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Android/IJ 2 | .idea/workspace.xml 3 | .idea/libraries 4 | local.properties 5 | *.iml 6 | build -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 chymtt 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-calendar-android 2 | 3 | A simple material-themed calendar for react native android 4 | 5 | Demo Screen Capture 6 | 7 | ## Installation Android 8 | 1. `npm install --save react-native-calendar-android` 9 | 10 | _Note_: Since react-native-calendar-android@0.0.3, you should use react-native@0.19.0 and above 11 | 12 | 2. In `android/settings.gradle` 13 | 14 | ```gradle 15 | ... 16 | include ':ReactNativeCalendarAndroid', ':app' 17 | project(':ReactNativeCalendarAndroid').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-calendar-android/android') 18 | ``` 19 | 20 | 3. In `android/app/build.gradle` 21 | 22 | ```gradle 23 | ... 24 | dependencies { 25 | ... 26 | compile project(':ReactNativeCalendarAndroid') 27 | } 28 | ``` 29 | 30 | 4. Register module (in MainActivity.java) 31 | 32 | 4.1. With RN < 0.19.0 33 | 34 | ```java 35 | import com.chymtt.reactnativecalendar.CalendarPackage; // <----- import 36 | 37 | public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { 38 | ...... 39 | 40 | @Override 41 | protected void onCreate(Bundle savedInstanceState) { 42 | super.onCreate(savedInstanceState); 43 | mReactRootView = new ReactRootView(this); 44 | 45 | mReactInstanceManager = ReactInstanceManager.builder() 46 | .setApplication(getApplication()) 47 | .setBundleAssetName("index.android.bundle") 48 | .setJSMainModuleName("index.android") 49 | .addPackage(new MainReactPackage()) 50 | .addPackage(new CalendarPackage()) // <------ add here 51 | .setUseDeveloperSupport(BuildConfig.DEBUG) 52 | .setInitialLifecycleState(LifecycleState.RESUMED) 53 | .build(); 54 | 55 | mReactRootView.startReactApplication(mReactInstanceManager, "ExampleRN", null); 56 | 57 | setContentView(mReactRootView); 58 | } 59 | ...... 60 | } 61 | ``` 62 | 63 | 4.2. With RN >= 0.19.0 64 | 65 | ```java 66 | import com.chymtt.reactnativecalendar.CalendarPackage; // <----- import 67 | 68 | public class MainActivity extends ReactActivity { 69 | ... 70 | 71 | @Override 72 | protected List getPackages() { 73 | return Arrays.asList( 74 | new MainReactPackage(), 75 | new CalendarPackage() // <------ add here 76 | ); 77 | } 78 | } 79 | ``` 80 | 81 | ## Usage 82 | 83 | ```js 84 | 85 | var Calendar = require('react-native-calendar-android'); 86 | ... 87 | 88 | render() { 89 | return ( 90 | { 101 | console.log(data); 102 | }} /> 103 | ); 104 | } 105 | ``` 106 | 107 | ## Notes 108 | 109 | The view is a grid with 7 tiles wide and 8 tiles high (with ```topbarVisible=true```), or 7 tiles high (with ```topbarVisible=false```) 110 | 111 | The size of each tile is automatically calculated based on the provided width. 112 | 113 | ## Props 114 | 115 | ### int width (required) 116 | 117 | Provide the width of the calendar. The height will be calculated based on width and ```topbarVisible```. 118 | 119 | ### boolean topbarVisible (default = true) 120 | 121 | Show/hide the top bar which contains the month's title and arrows to go to previous or next months. 122 | 123 | ### string arrowColor 124 | 125 | A string color in the format #RRGGBB or #AARRGGBB. It changes color of the top bar's arrows accordingly. 126 | 127 | ### enum firstDayOfWeek (default = 'sunday') 128 | 129 | enum [ 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday' ] 130 | 131 | Set the first day of the week. 132 | 133 | ### enum showDate (default = 'current') 134 | 135 | enum [ 'all', 'current' ] 136 | 137 | If set to ```current```, only show dates within current month. If set to ```all```, show dates from previous and current months too. 138 | 139 | ### array currentDate 140 | 141 | Set the focus of the calendar. Due to some limitations, you must provide an array with only one element, which is the currentDate. currentDate can be a string in the format ```yyyy/mm/dd``` or a timestamp. 142 | 143 | ### enum selectionMode (default = 'single') 144 | 145 | enum [ 'none', 'single', 'multiple' ] 146 | 147 | Set the selection mode. 148 | 149 | - none: you cannot select date 150 | - single: you can only select one date at a time 151 | - multiple: you can select multiple dates 152 | 153 | ### string selectionColor 154 | 155 | Set the color of the selection circle. Should be a color in the format #RRGGBB or #AARRGGBB. 156 | 157 | ### array selectedDates 158 | 159 | An array of dates in the format ```yyyy/mm/dd``` or timestamp. Set the selected dates on the calendar. 160 | 161 | ## Event 162 | 163 | ### onDateChange(data) 164 | 165 | Called when user select/deselect a date. The returned data is { date: 'yyyy/mm/dd', selected: boolean } 166 | 167 | ## Questions or suggestions? 168 | 169 | Feel free to [open an issue](https://github.com/chymtt/ReactNativeCalendarAndroid/issues) 170 | [Pull requests](https://github.com/chymtt/ReactNativeCalendarAndroid/pulls) are also welcome 171 | 172 | ## Credit 173 | 174 | Big thanks to @prolificinteractive for their awesome [Material Calendar View](https://github.com/prolificinteractive/material-calendarview) 175 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | minSdkVersion 16 9 | targetSdkVersion 22 10 | versionCode 1 11 | versionName "1.0" 12 | ndk { 13 | abiFilters "armeabi-v7a", "x86" 14 | } 15 | } 16 | } 17 | 18 | dependencies { 19 | compile 'com.android.support:appcompat-v7:23.0.0' 20 | compile 'com.facebook.react:react-native:0.32.+' 21 | compile 'com.prolificinteractive:material-calendarview:1.4.0' 22 | } 23 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/main/java/com/chymtt/reactnativecalendar/Calendar.java: -------------------------------------------------------------------------------- 1 | package com.chymtt.reactnativecalendar; 2 | 3 | import android.view.ViewGroup; 4 | 5 | import com.facebook.react.uimanager.ThemedReactContext; 6 | import com.prolificinteractive.materialcalendarview.MaterialCalendarView; 7 | 8 | /** 9 | * Created by Chym on 29/11/15. 10 | */ 11 | public class Calendar extends MaterialCalendarView { 12 | 13 | public Calendar(ThemedReactContext context) { 14 | super(context); 15 | setLayoutParams(new ViewGroup.LayoutParams( 16 | ViewGroup.LayoutParams.MATCH_PARENT, 17 | ViewGroup.LayoutParams.WRAP_CONTENT 18 | )); 19 | } 20 | 21 | private final Runnable mLayoutRunnable = new Runnable() { 22 | @Override 23 | public void run() { 24 | measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY), 25 | MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY)); 26 | layout(getLeft(), getTop(), getRight(), getBottom()); 27 | } 28 | }; 29 | 30 | @Override 31 | public void requestLayout() { 32 | super.requestLayout(); 33 | post(mLayoutRunnable); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /android/src/main/java/com/chymtt/reactnativecalendar/CalendarEvent.java: -------------------------------------------------------------------------------- 1 | package com.chymtt.reactnativecalendar; 2 | 3 | import android.util.Log; 4 | 5 | import com.facebook.react.bridge.Arguments; 6 | import com.facebook.react.bridge.WritableMap; 7 | import com.facebook.react.uimanager.events.Event; 8 | import com.facebook.react.uimanager.events.RCTEventEmitter; 9 | import com.prolificinteractive.materialcalendarview.CalendarDay; 10 | 11 | import java.text.DateFormat; 12 | import java.text.SimpleDateFormat; 13 | 14 | /** 15 | * Created by Chym on 29/11/15. 16 | */ 17 | public class CalendarEvent extends Event{ 18 | public static final String EVENT_NAME = "topDateChange"; 19 | 20 | private static final String DATE_FORMAT = "yyyy/MM/dd"; 21 | private static final DateFormat dateFormat; 22 | static { 23 | dateFormat = new SimpleDateFormat(DATE_FORMAT); 24 | } 25 | 26 | private final CalendarDay date; 27 | private final boolean selected; 28 | 29 | public CalendarEvent(int viewId, CalendarDay date, boolean selected) { 30 | super(viewId); 31 | this.date = date; 32 | this.selected = selected; 33 | } 34 | 35 | public String getDate() { 36 | return dateFormat.format(date.getDate()); 37 | } 38 | 39 | public boolean isSelected() { 40 | return selected; 41 | } 42 | 43 | @Override 44 | public String getEventName() { 45 | return EVENT_NAME; 46 | } 47 | 48 | @Override 49 | public short getCoalescingKey() { 50 | return 0; 51 | } 52 | 53 | @Override 54 | public void dispatch(RCTEventEmitter rctEventEmitter) { 55 | rctEventEmitter.receiveEvent(getViewTag(), getEventName(), serializeEventData()); 56 | } 57 | 58 | private WritableMap serializeEventData() { 59 | WritableMap eventData = Arguments.createMap(); 60 | eventData.putString("date", getDate()); 61 | eventData.putBoolean("selected", isSelected()); 62 | return eventData; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /android/src/main/java/com/chymtt/reactnativecalendar/CalendarManager.java: -------------------------------------------------------------------------------- 1 | package com.chymtt.reactnativecalendar; 2 | 3 | import android.graphics.Color; 4 | import android.os.SystemClock; 5 | 6 | import com.facebook.react.bridge.JSApplicationIllegalArgumentException; 7 | import com.facebook.react.bridge.ReadableArray; 8 | import com.facebook.react.common.MapBuilder; 9 | import com.facebook.react.uimanager.annotations.ReactProp; 10 | import com.facebook.react.uimanager.SimpleViewManager; 11 | import com.facebook.react.uimanager.ThemedReactContext; 12 | import com.facebook.react.uimanager.UIManagerModule; 13 | import com.prolificinteractive.materialcalendarview.CalendarDay; 14 | import com.prolificinteractive.materialcalendarview.MaterialCalendarView; 15 | import com.prolificinteractive.materialcalendarview.OnDateSelectedListener; 16 | 17 | import java.text.DateFormat; 18 | import java.text.ParseException; 19 | import java.text.SimpleDateFormat; 20 | import java.util.ArrayList; 21 | import java.util.Date; 22 | import java.util.Map; 23 | 24 | import javax.annotation.Nullable; 25 | 26 | /** 27 | * Created by Chym on 29/11/15. 28 | */ 29 | public class CalendarManager extends SimpleViewManager { 30 | public static final String REACT_CLASS = "CalendarAndroid"; 31 | 32 | private static final String DATE_FORMAT = "yyyy/MM/dd"; 33 | private static final DateFormat dateFormat; 34 | static { 35 | dateFormat = new SimpleDateFormat(DATE_FORMAT); 36 | } 37 | 38 | private static final String COLOR_REGEX = "^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$"; 39 | 40 | @Override 41 | public String getName() { 42 | return REACT_CLASS; 43 | } 44 | 45 | @Override 46 | protected Calendar createViewInstance(ThemedReactContext context) { 47 | return new Calendar(context); 48 | } 49 | 50 | @Nullable 51 | @Override 52 | public Map getExportedCustomBubblingEventTypeConstants() { 53 | return MapBuilder.builder() 54 | .put( 55 | "topDateChange", 56 | MapBuilder.of( 57 | "phasedRegistrationNames", 58 | MapBuilder.of( 59 | "bubbled", "onDateChange", "captured", "onDateChangeCapture"))) 60 | .build(); 61 | } 62 | 63 | @Override 64 | protected void addEventEmitters(final ThemedReactContext reactContext, final Calendar view) { 65 | view.setOnDateChangedListener(new OnDateSelectedListener() { 66 | @Override 67 | public void onDateSelected(MaterialCalendarView widget, CalendarDay date, boolean selected) { 68 | reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher() 69 | .dispatchEvent(new CalendarEvent( 70 | view.getId(), 71 | date, 72 | selected)); 73 | } 74 | }); 75 | } 76 | 77 | @ReactProp(name = "topbarVisible") 78 | public void setTopbarVisible(Calendar view, boolean topbarVisible) { 79 | view.setTopbarVisible(topbarVisible); 80 | } 81 | 82 | @ReactProp(name = "arrowColor") 83 | public void setArrowColor(Calendar view, String color) { 84 | if (color != null) { 85 | if (color.matches(COLOR_REGEX)) { 86 | view.setArrowColor(Color.parseColor(color)); 87 | } else { 88 | throw new JSApplicationIllegalArgumentException("Invalid arrowColor property: " + color); 89 | } 90 | } 91 | } 92 | 93 | @ReactProp(name = "firstDayOfWeek") 94 | public void setFirstDayOfWeek(Calendar view, String firstDayOfWeek) { 95 | if (firstDayOfWeek != null) { 96 | view.state().edit() 97 | .setFirstDayOfWeek(getFirstDayOfWeekFromString(firstDayOfWeek)) 98 | .commit(); 99 | } 100 | } 101 | 102 | @ReactProp(name = "showDate") 103 | public void setShowDate(Calendar view, String showDate) { 104 | if (showDate != null) { 105 | if (showDate.equals("all")) { 106 | view.setShowOtherDates(MaterialCalendarView.SHOW_OTHER_MONTHS); 107 | } else if (showDate.equals("current")) { 108 | view.setShowOtherDates(MaterialCalendarView.SHOW_DEFAULTS); 109 | } else { 110 | throw new JSApplicationIllegalArgumentException("Unknown showDate property: " + showDate); 111 | } 112 | } 113 | } 114 | 115 | @ReactProp(name = "currentDate") 116 | public void setCurrentDate(Calendar view, ReadableArray data) { 117 | String type = data.getType(0).name(); 118 | if ("String".equals(type)) { 119 | try { 120 | Date date = dateFormat.parse(data.getString(0)); 121 | view.setCurrentDate(date); 122 | } catch (ParseException e) { 123 | throw new JSApplicationIllegalArgumentException("Invalid date format: " + data.getString(0)); 124 | } 125 | } else if ("Number".equals(type)) { 126 | Double value = data.getDouble(0); 127 | Date date = new Date(value.longValue()); 128 | view.setCurrentDate(date); 129 | } else { 130 | throw new JSApplicationIllegalArgumentException("Invalid date format: " + data.getString(0)); 131 | } 132 | } 133 | 134 | @ReactProp(name = "minimumDate") 135 | public void setMinimumDate(Calendar view, ReadableArray data) { 136 | String type = data.getType(0).name(); 137 | if ("String".equals(type)) { 138 | try { 139 | Date date = dateFormat.parse(data.getString(0)); 140 | if (shouldUpdateMinMaxDate(view.getMinimumDate(), date)) { 141 | view.state().edit() 142 | .setMinimumDate(date) 143 | .commit(); 144 | } 145 | } catch (ParseException e) { 146 | throw new JSApplicationIllegalArgumentException("Invalid date format: " + data.getString(0)); 147 | } 148 | } else if ("Number".equals(type)) { 149 | Double value = data.getDouble(0); 150 | Date date = new Date(value.longValue()); 151 | if (shouldUpdateMinMaxDate(view.getMinimumDate(), date)) { 152 | view.state().edit() 153 | .setMinimumDate(date) 154 | .commit(); 155 | } 156 | } else { 157 | throw new JSApplicationIllegalArgumentException("Invalid date format: " + data.getString(0)); 158 | } 159 | } 160 | 161 | @ReactProp(name = "maximumDate") 162 | public void setMaximumDate(Calendar view, ReadableArray data) { 163 | String type = data.getType(0).name(); 164 | 165 | if ("String".equals(type)) { 166 | try { 167 | Date date = dateFormat.parse(data.getString(0)); 168 | if (shouldUpdateMinMaxDate(view.getMaximumDate(), date)) { 169 | view.state().edit() 170 | .setMaximumDate(date) 171 | .commit(); 172 | } 173 | } catch (ParseException e) { 174 | throw new JSApplicationIllegalArgumentException("Invalid date format: " + data.getString(0)); 175 | } 176 | } else if ("Number".equals(type)) { 177 | Double value = data.getDouble(0); 178 | Date date = new Date(value.longValue()); 179 | 180 | if (shouldUpdateMinMaxDate(view.getMaximumDate(), date)) { 181 | view.state().edit() 182 | .setMaximumDate(date) 183 | .commit(); 184 | } 185 | } else { 186 | throw new JSApplicationIllegalArgumentException("Invalid date format: " + data.getString(0)); 187 | } 188 | } 189 | 190 | @ReactProp(name = "selectionMode") 191 | public void setSelectionMode(Calendar view, String mode) { 192 | if (mode != null) { 193 | if (mode.equals("none")) { 194 | view.setSelectionMode(MaterialCalendarView.SELECTION_MODE_NONE); 195 | } else if (mode.equals("single")) { 196 | view.setSelectionMode(MaterialCalendarView.SELECTION_MODE_SINGLE); 197 | } else if (mode.equals("multiple")) { 198 | view.setSelectionMode(MaterialCalendarView.SELECTION_MODE_MULTIPLE); 199 | } else { 200 | throw new JSApplicationIllegalArgumentException("Unknown selectionMode property: " + mode); 201 | } 202 | } 203 | } 204 | 205 | @ReactProp(name = "selectionColor") 206 | public void setSelectionColor(Calendar view, String color) { 207 | if (color != null) { 208 | if (color.matches(COLOR_REGEX)) { 209 | view.setSelectionColor(Color.parseColor(color)); 210 | } else { 211 | throw new JSApplicationIllegalArgumentException("Invalid selectionColor property: " + color); 212 | } 213 | } 214 | } 215 | 216 | @ReactProp(name = "selectedDates") 217 | public void setSelectedDates(Calendar view, ReadableArray dates) { 218 | ArrayList selectedDates = new ArrayList(); 219 | for (int i = 0; i < dates.size(); i++) { 220 | String type = dates.getType(i).name(); 221 | if ("String".equals(type)) { 222 | try { 223 | Date date = dateFormat.parse(dates.getString(i)); 224 | selectedDates.add(date); 225 | } catch (ParseException e) { 226 | throw new JSApplicationIllegalArgumentException("Invalid date format: " + dates.getString(i)); 227 | } 228 | } else if ("Number".equals(type)) { 229 | Double value = dates.getDouble(i); 230 | Date date = new Date(value.longValue()); 231 | selectedDates.add(date); 232 | } else { 233 | throw new JSApplicationIllegalArgumentException("Invalid date format: " + dates.getString(i)); 234 | } 235 | } 236 | for (Date date : selectedDates) { 237 | view.setDateSelected(date, true); 238 | } 239 | } 240 | 241 | private int getFirstDayOfWeekFromString(String firstDayOfWeek) { 242 | if (firstDayOfWeek.equals("monday")) { 243 | return java.util.Calendar.MONDAY; 244 | } else if (firstDayOfWeek.equals("tuesday")) { 245 | return java.util.Calendar.TUESDAY; 246 | } else if (firstDayOfWeek.equals("wednesday")) { 247 | return java.util.Calendar.WEDNESDAY; 248 | } else if (firstDayOfWeek.equals("thursday")) { 249 | return java.util.Calendar.THURSDAY; 250 | } else if (firstDayOfWeek.equals("friday")) { 251 | return java.util.Calendar.FRIDAY; 252 | } else if (firstDayOfWeek.equals("saturday")) { 253 | return java.util.Calendar.SATURDAY; 254 | } else if (firstDayOfWeek.equals("sunday")) { 255 | return java.util.Calendar.SUNDAY; 256 | } else { 257 | throw new JSApplicationIllegalArgumentException("Unknown firstDayOfWeek property: " + firstDayOfWeek); 258 | } 259 | } 260 | 261 | /** 262 | * Should update new value of minimum or maximum date 263 | * 264 | * Check if the new min or max date is different from the previous one, if yes we update otherwise we don't. 265 | * 266 | * @param minMaxDate 267 | * @param newDate 268 | * @return boolean 269 | */ 270 | private boolean shouldUpdateMinMaxDate(CalendarDay minMaxDate, Date newDate) { 271 | if (minMaxDate == null) { 272 | return true; 273 | } 274 | 275 | java.util.Calendar newDateCalendar = java.util.Calendar.getInstance(); 276 | newDateCalendar.setTimeInMillis(newDate.getTime()); 277 | 278 | return (minMaxDate.getYear() != newDateCalendar.get(java.util.Calendar.YEAR) && 279 | minMaxDate.getMonth() != newDateCalendar.get(java.util.Calendar.MONTH) && 280 | minMaxDate.getDay() != newDateCalendar.get(java.util.Calendar.DAY_OF_MONTH)); 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /android/src/main/java/com/chymtt/reactnativecalendar/CalendarPackage.java: -------------------------------------------------------------------------------- 1 | package com.chymtt.reactnativecalendar; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.List; 12 | 13 | /** 14 | * Created by Chym on 29/11/15. 15 | */ 16 | public class CalendarPackage implements ReactPackage { 17 | @Override 18 | public List createNativeModules(ReactApplicationContext reactApplicationContext) { 19 | return new ArrayList(); 20 | } 21 | 22 | @Override 23 | public List createViewManagers(ReactApplicationContext reactApplicationContext) { 24 | return Arrays.asList( 25 | new CalendarManager() 26 | ); 27 | } 28 | 29 | @Override 30 | public List> createJSModules() { 31 | return Arrays.asList(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /android/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-calendar-android", 3 | "version": "0.0.6", 4 | "description": "A simple material-themed calendar for react native android", 5 | "main": "src/Calendar.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/chymtt/ReactNativeCalendarAndroid" 9 | }, 10 | "keywords": [ 11 | "react-component", 12 | "react-native", 13 | "android", 14 | "material", 15 | "material-design", 16 | "calendar" 17 | ], 18 | "author": "Do Anh Tu ", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/chymtt/ReactNativeCalendarAndroid/issues" 22 | }, 23 | "homepage": "https://github.com/chymtt/ReactNativeCalendarAndroid" 24 | } 25 | -------------------------------------------------------------------------------- /src/Calendar.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require('react'); 4 | var ReactNative = require('react-native'); 5 | var { requireNativeComponent, PropTypes, View } = ReactNative; 6 | 7 | var NativeCalendar = requireNativeComponent('CalendarAndroid', Calendar); 8 | 9 | var FIRST_DAY_OF_WEEK = [ 10 | 'monday', 11 | 'tuesday', 12 | 'wednesday', 13 | 'thursday', 14 | 'friday', 15 | 'saturday', 16 | 'sunday' 17 | ]; 18 | 19 | var SHOWING_DATE = [ 20 | 'all', 21 | 'current' 22 | ]; 23 | 24 | var SELECTION_MODES = [ 25 | 'none', 26 | 'single', 27 | 'multiple' 28 | ]; 29 | 30 | var colorType = function (props, propName, componentName) { 31 | var checker = function() { 32 | var color = props[propName]; 33 | var regex = /^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/; 34 | if (!regex.test(color)) { 35 | return new Error('Only accept color formats: #RRGGBB and #AARRGGBB'); 36 | } 37 | }; 38 | 39 | return PropTypes.string(props, propName, componentName) || checker(); 40 | } 41 | 42 | class Calendar extends React.Component { 43 | constructor() { 44 | super(); 45 | this._onDateChange = this._onDateChange.bind(this); 46 | } 47 | 48 | _onDateChange(event) { 49 | this.props.onDateChange && this.props.onDateChange(event.nativeEvent); 50 | } 51 | 52 | render() { 53 | var { style, ...rest } = this.props, 54 | width = rest.width, 55 | height = rest.topbarVisible ? width / 7 * 8 : width; 56 | 57 | style = { 58 | ...style, 59 | width, 60 | height 61 | }; 62 | 63 | return ( 64 | 68 | ); 69 | } 70 | } 71 | 72 | Calendar.propTypes = { 73 | ...View.propTypes, 74 | width: PropTypes.number.isRequired, 75 | topbarVisible: PropTypes.bool, 76 | arrowColor: colorType, 77 | firstDayOfWeek: PropTypes.oneOf(FIRST_DAY_OF_WEEK), 78 | showDate: PropTypes.oneOf(SHOWING_DATE), 79 | currentDate: PropTypes.arrayOf(PropTypes.oneOfType([ PropTypes.string, PropTypes.number ])), 80 | selectionMode: PropTypes.oneOf(SELECTION_MODES), 81 | selectionColor: colorType, 82 | selectedDates: PropTypes.arrayOf(PropTypes.oneOfType([ PropTypes.string, PropTypes.number ])) 83 | }; 84 | 85 | Calendar.defaultProps = { 86 | topbarVisible: true 87 | } 88 | 89 | module.exports = Calendar; 90 | --------------------------------------------------------------------------------