├── .eslintrc.js
├── .gitignore
├── .npmignore
├── .nvmrc
├── .travis.yml
├── ISSUE_TEMPLATE.md
├── LICENSE
├── README.md
├── demo
├── agenda.gif
├── calendar-list.gif
├── calendar.gif
├── custom.png
├── horizontal-calendar-list.gif
├── loader.png
├── marking1.png
├── marking2.png
├── marking3.png
├── marking4.png
├── marking5.png
└── marking6.png
├── example
├── .babelrc
├── .buckconfig
├── .flowconfig
├── .gitattributes
├── .gitignore
├── .watchmanconfig
├── __tests__
│ ├── index.android.js
│ └── index.ios.js
├── android
│ ├── app
│ │ ├── BUCK
│ │ ├── build.gradle
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── calendarsexample
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── MainApplication.java
│ │ │ └── res
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── keystores
│ │ ├── BUCK
│ │ └── debug.keystore.properties
│ └── settings.gradle
├── app.json
├── index.android.js
├── index.ios.js
├── ios
│ ├── CalendarsExample-tvOS
│ │ └── Info.plist
│ ├── CalendarsExample-tvOSTests
│ │ └── Info.plist
│ ├── CalendarsExample.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ ├── CalendarsExample-tvOS.xcscheme
│ │ │ └── CalendarsExample.xcscheme
│ ├── CalendarsExample
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.xib
│ │ ├── Images.xcassets
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ └── main.m
│ └── CalendarsExampleTests
│ │ ├── CalendarsExampleTests.m
│ │ └── Info.plist
├── package.json
└── src
│ ├── app.js
│ └── screens
│ ├── agenda.js
│ ├── calendars.js
│ ├── calendarsList.js
│ ├── horizontalCalendarList.js
│ ├── index.js
│ └── menu.js
├── package.json
├── pom.xml
├── spec
├── runner.js
└── support
│ └── jasmine.json
└── src
├── agenda
├── img
│ └── knob@2x.png
├── index.js
├── platform-style.ios.js
├── platform-style.js
├── reservation-list
│ ├── index.js
│ ├── reservation.js
│ └── style.js
└── style.js
├── calendar-list
├── index.js
├── item.js
└── style.js
├── calendar
├── day
│ ├── basic
│ │ ├── index.js
│ │ └── style.js
│ ├── custom
│ │ ├── index.js
│ │ └── style.js
│ ├── multi-dot
│ │ ├── index.js
│ │ └── style.js
│ ├── multi-period
│ │ ├── index.js
│ │ └── style.js
│ └── period
│ │ ├── index.js
│ │ └── style.js
├── header
│ ├── index.js
│ └── style.js
├── img
│ ├── next.png
│ ├── next@1.5x.android.png
│ ├── next@2x.android.png
│ ├── next@2x.ios.png
│ ├── next@3x.android.png
│ ├── next@4x.android.png
│ ├── previous.png
│ ├── previous@1.5x.android.png
│ ├── previous@2x.android.png
│ ├── previous@2x.ios.png
│ ├── previous@3x.android.png
│ └── previous@4x.android.png
├── index.js
├── style.js
└── updater.js
├── component-updater.js
├── component-updater.spec.js
├── dateutils.js
├── dateutils.spec.js
├── index.js
├── input.js
├── interface.js
├── interface.spec.js
├── style.js
└── testIDs.js
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "env": {
3 | "es6": true,
4 | "node": true
5 | },
6 | "globals": {
7 | "expect": true,
8 | "it": true,
9 | "describe": true,
10 | },
11 | "extends": "eslint:recommended",
12 | "parser": "babel-eslint",
13 | "parserOptions": {
14 | "ecmaFeatures": {
15 | "experimentalObjectRestSpread": true,
16 | "jsx": true
17 | },
18 | "sourceType": "module"
19 | },
20 | "plugins": [
21 | "react"
22 | ],
23 | "rules": {
24 | "no-unused-vars": 2,
25 | "react/jsx-uses-vars": 2,
26 | "react/jsx-uses-react": 2,
27 | "indent": [
28 | "error",
29 | 2
30 | ],
31 | "linebreak-style": [
32 | "error",
33 | "unix"
34 | ],
35 | "quotes": [
36 | "error",
37 | "single"
38 | ],
39 | "semi": [
40 | "error",
41 | "always"
42 | ]
43 | }
44 | };
45 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | npm-debug.log
4 | .idea
5 | yarn.lock
6 | .vscode
7 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .idea
3 | src/**/*.spec.js
4 | example/
5 | demo/
6 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 6.9
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "7"
4 |
5 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Please make our job easier by filling this template out to completion. If you're requesting a feature instead of reporting a bug, please feel free to skip the Environment and Reproducible Demo sections.
2 |
3 | ## Description
4 |
5 | 1-2 sentences describing the problem you're having or the feature you'd like to request
6 |
7 | ## Expected Behavior
8 |
9 | What action did you perform, and what did you expect to happen?
10 |
11 | ## Observed Behavior
12 |
13 | What actually happened when you performed the above actions?
14 |
15 | If there's an error message, please paste the *full terminal output and error message* in this code block:
16 |
17 | ```
18 | Error text goes here!
19 | ```
20 |
21 | ## Environment
22 |
23 | Please run these commands in the project folder and fill in their results:
24 |
25 | * `npm ls react-native-calendars`:
26 | * `npm ls react-native`:
27 |
28 | Also specify:
29 |
30 | 1. Phone/emulator/simulator & version:
31 |
32 | ## Reproducible Demo
33 |
34 | Please provide a minimized reproducible demonstration of the problem you're reporting.
35 |
36 | Issues that come with minimal repro's are resolved much more quickly than issues where a maintainer has to reproduce themselves.
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Wix.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Native Calendars ✨ 🗓️ 📆
2 |
3 | [](https://www.npmjs.com/package/react-native-calendars)
4 | [](https://travis-ci.org/wix/react-native-calendars)
5 |
6 | This module includes various customizable react native calendar components.
7 |
8 | The package is both **Android** and **iOS** compatible.
9 |
10 | ## Try it out
11 |
12 | You can run example module by performing these steps:
13 |
14 | ```
15 | $ git clone git@github.com:wix/react-native-calendars.git
16 | $ cd react-native-calendars/example
17 | $ npm install
18 | $ react-native run-ios
19 | ```
20 |
21 | You can check example screens source code in [example module screens](https://github.com/wix-private/wix-react-native-calendar/tree/master/example/src/screens)
22 |
23 | This project is compatible with Expo/CRNA (without ejecting), and the examples have been [published on Expo](https://expo.io/@community/react-native-calendars-example)
24 |
25 | ## Installation
26 |
27 | ```
28 | $ npm install --save react-native-calendars
29 | ```
30 |
31 | The solution is implemented in JavaScript so no native module linking is required.
32 |
33 | ## Usage
34 |
35 | `import {` [Calendar](#calendar), [CalendarList](#calendarlist), [Agenda](#agenda) `} from 'react-native-calendars';`
36 |
37 | All parameters for components are optional. By default the month of current local date will be displayed.
38 |
39 | Event handler callbacks are called with `calendar objects` like this:
40 |
41 | ```javasctipt
42 | {
43 | day: 1, // day of month (1-31)
44 | month: 1, // month of year (1-12)
45 | year: 2017, // year
46 | timestamp, // UTC timestamp representing 00:00 AM of this date
47 | dateString: '2016-05-13' // date formatted as 'YYYY-MM-DD' string
48 | }
49 | ```
50 |
51 | Parameters that require date types accept YYYY-MM-DD formated datestrings, JavaScript date objects, `calendar objects` and UTC timestamps.
52 |
53 | Calendars can be localized by adding custom locales to `LocaleConfig` object:
54 |
55 | ```javascript
56 | import {LocaleConfig} from 'react-native-calendars';
57 |
58 | LocaleConfig.locales['fr'] = {
59 | monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'],
60 | monthNamesShort: ['Janv.','Févr.','Mars','Avril','Mai','Juin','Juil.','Août','Sept.','Oct.','Nov.','Déc.'],
61 | dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'],
62 | dayNamesShort: ['Dim.','Lun.','Mar.','Mer.','Jeu.','Ven.','Sam.']
63 | };
64 |
65 | LocaleConfig.defaultLocale = 'fr';
66 | ```
67 |
68 | ### Calendar
69 |
70 |
71 |
72 |
73 |
74 | #### Basic parameters
75 |
76 | ```javascript
77 | {console.log('selected day', day)}}
86 | // Handler which gets executed on day long press. Default = undefined
87 | onDayLongPress={(day) => {console.log('selected day', day)}}
88 | // Month format in calendar title. Formatting values: http://arshaw.com/xdate/#Formatting
89 | monthFormat={'yyyy MM'}
90 | // Handler which gets executed when visible month changes in calendar. Default = undefined
91 | onMonthChange={(month) => {console.log('month changed', month)}}
92 | // Hide month navigation arrows. Default = false
93 | hideArrows={true}
94 | // Replace default arrows with custom ones (direction can be 'left' or 'right')
95 | renderArrow={(direction) => ()}
96 | // Do not show days of other months in month page. Default = false
97 | hideExtraDays={true}
98 | // If hideArrows=false and hideExtraDays=false do not switch month when tapping on greyed out
99 | // day from another month that is visible in calendar page. Default = false
100 | disableMonthChange={true}
101 | // If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
102 | firstDay={1}
103 | // Hide day names. Default = false
104 | hideDayNames={true}
105 | // Show week numbers to the left. Default = false
106 | showWeekNumbers={true}
107 | // Handler which gets executed when press arrow icon left. It receive a callback can go back month
108 | onPressArrowLeft={substractMonth => substractMonth()}
109 | // Handler which gets executed when press arrow icon left. It receive a callback can go next month
110 | onPressArrowRight={addMonth => addMonth()}
111 | />
112 | ```
113 |
114 | #### Date marking
115 |
116 | **!Disclaimer!** Make sure that `markedDates` param is immutable. If you change `markedDates` object content but the reference to it does not change calendar update will not be triggered.
117 |
118 | Dot marking
119 |
120 |
121 |
122 |
123 |
124 | ```javascript
125 |
134 | ```
135 |
136 | You can customise a dot color for each day independently.
137 |
138 | Multi-Dot marking
139 |
140 |
141 |
142 |
143 |
144 | Use markingType = 'multi-dot' if you want to display more than one dot. Both the Calendar and CalendarList control support multiple dots by using 'dots' array in markedDates. The property 'color' is mandatory while 'key' and 'selectedColor' are optional. If key is omitted then the array index is used as key. If selectedColor is omitted then 'color' will be used for selected dates.
145 | ```javascript
146 | const vacation = {key:'vacation', color: 'red', selectedDotColor: 'blue'};
147 | const massage = {key:'massage', color: 'blue', selectedDotColor: 'blue'};
148 | const workout = {key:'workout', color: 'green'};
149 |
150 |
157 | ```
158 |
159 |
160 | Period marking
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 | ```javascript
171 |
182 | ```
183 |
184 | Multi-period marking
185 |
186 |
187 |
188 |
189 |
190 | CAUTION: This marking is only fully supported by the `` component because it expands its height. Usage with `` might lead to overflow issues.
191 |
192 | ```javascript
193 |
213 | ```
214 |
215 | Custom marking allows you to customize each marker with custom styles.
216 |
217 |
218 |
219 |
220 |
221 | ```javascript
222 |
249 | ```
250 |
251 | Keep in mind that different marking types are not compatible. You can use just one marking style for calendar.
252 |
253 | #### Displaying data loading indicator
254 |
255 |
256 |
257 |
258 |
259 | The loading indicator next to month name will be displayed if `` has `displayLoadingIndicator` property and `markedDays` collection does not have a value for every day of the month in question. When you load data for days, just set `[]` or special marking value to all days in `markedDates` collection.
260 |
261 | #### Customizing look & feel
262 |
263 | ```javascript
264 |
294 | ```
295 |
296 | #### Advanced styling
297 |
298 | If you want to have complete control over calendar styles you can do it by overriding default style.js files. For example, if you want to override calendar header style first you have to find stylesheet id for this file:
299 |
300 | https://github.com/wix/react-native-calendars/blob/master/src/calendar/header/style.js#L4
301 |
302 | In this case it is 'stylesheet.calendar.header'. Next you can add overriding stylesheet to your theme with this id.
303 |
304 | https://github.com/wix/react-native-calendars/blob/master/example/src/screens/calendars.js#L56
305 |
306 | ```javascript
307 | theme={{
308 | arrowColor: 'white',
309 | 'stylesheet.calendar.header': {
310 | week: {
311 | marginTop: 5,
312 | flexDirection: 'row',
313 | justifyContent: 'space-between'
314 | }
315 | }
316 | }}
317 | ```
318 |
319 | **Disclaimer**: issues that arise because something breaks after using stylesheet override will not be supported. Use this option at your own risk.
320 |
321 | #### Overriding day component
322 |
323 | If you need custom functionality not supported by current day component implementations you can pass your own custom day
324 | component to the calendar.
325 |
326 | ```javascript
327 | {
330 | return ({date.day});
331 | }}
332 | />
333 | ```
334 |
335 | The dayComponent prop has to receive a RN component or function that receive props. The day component will receive such props:
336 |
337 | * state - disabled if the day should be disabled (this is decided by base calendar component)
338 | * marking - markedDates value for this day
339 | * date - the date object representing this day
340 |
341 | **Tip:** Don't forget to implement shouldComponentUpdate for your custom day component to make calendar perform better
342 |
343 | If you implement an awesome day component please make a PR so that other people could use it :)
344 |
345 | ### CalendarList
346 |
347 |
348 |
349 |
350 |
351 | `` is scrollable semi-infinite calendar composed of `` components. Currently it is possible to scroll 4 years back and 4 years to the future. All paramters that are available for `` are also available for this component. There are also some additional params that can be used:
352 |
353 | ```javascript
354 | {console.log('now these months are visible', months);}}
357 | // Max amount of months allowed to scroll to the past. Default = 50
358 | pastScrollRange={50}
359 | // Max amount of months allowed to scroll to the future. Default = 50
360 | futureScrollRange={50}
361 | // Enable or disable scrolling of calendar list
362 | scrollEnabled={true}
363 | // Enable or disable vertical scroll indicator. Default = false
364 | showScrollIndicator={true}
365 | ...calendarParams
366 | />
367 | ```
368 |
369 | #### Horizontal CalendarList
370 |
371 |
372 |
373 |
374 |
375 | You can also make the `CalendarList` scroll horizontally. To do that you need to pass specific props to the `CalendarList`:
376 |
377 | ```javascript
378 |
388 | ```
389 |
390 | ### Agenda
391 |
392 |
393 |
394 |
395 | An advanced agenda component that can display interactive listings for calendar day items.
396 |
397 | ```javascript
398 | {console.log('trigger items loading')}}
410 | // callback that fires when the calendar is opened or closed
411 | onCalendarToggled={(calendarOpened) => {console.log(calendarOpened)}}
412 | // callback that gets called on day press
413 | onDayPress={(day)=>{console.log('day pressed')}}
414 | // callback that gets called when day changes while scrolling agenda list
415 | onDayChange={(day)=>{console.log('day changed')}}
416 | // initially selected day
417 | selected={'2012-05-16'}
418 | // Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
419 | minDate={'2012-05-10'}
420 | // Maximum date that can be selected, dates after maxDate will be grayed out. Default = undefined
421 | maxDate={'2012-05-30'}
422 | // Max amount of months allowed to scroll to the past. Default = 50
423 | pastScrollRange={50}
424 | // Max amount of months allowed to scroll to the future. Default = 50
425 | futureScrollRange={50}
426 | // specify how each item should be rendered in agenda
427 | renderItem={(item, firstItemInDay) => {return ();}}
428 | // specify how each date should be rendered. day can be undefined if the item is not first in that day.
429 | renderDay={(day, item) => {return ();}}
430 | // specify how empty date content with no items should be rendered
431 | renderEmptyDate={() => {return ();}}
432 | // specify how agenda knob should look like
433 | renderKnob={() => {return ();}}
434 | // specify what should be rendered instead of ActivityIndicator
435 | renderEmptyData = {() => {return ();}}
436 | // specify your item comparison function for increased performance
437 | rowHasChanged={(r1, r2) => {return r1.text !== r2.text}}
438 | // Hide knob button. Default = false
439 | hideKnob={true}
440 | // By default, agenda dates are marked if they have at least one item, but you can override this if needed
441 | markedDates={{
442 | '2012-05-16': {selected: true, marked: true},
443 | '2012-05-17': {marked: true},
444 | '2012-05-18': {disabled: true}
445 | }}
446 | // If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make sure to also set the refreshing prop correctly.
447 | onRefresh={() => console.log('refreshing...')}
448 | // Set this true while waiting for new data from a refresh
449 | refreshing={false}
450 | // Add a custom RefreshControl component, used to provide pull-to-refresh functionality for the ScrollView.
451 | refreshControl={null}
452 | // agenda theme
453 | theme={{
454 | ...calendarTheme,
455 | agendaDayTextColor: 'yellow',
456 | agendaDayNumColor: 'green',
457 | agendaTodayColor: 'red',
458 | agendaKnobColor: 'blue'
459 | }}
460 | // agenda container style
461 | style={{}}
462 | />
463 | ```
464 |
465 | ## Authors
466 |
467 | * [Tautvilas Mecinskas](https://github.com/tautvilas/) - Initial code - [@tautvilas](https://twitter.com/TautviIas)
468 | * Katrin Zotchev - Initial design - [@katrin_zot](https://twitter.com/katrin_zot)
469 |
470 | See also the list of [contributors](https://github.com/wix/react-native-calendar-components/contributors) who participated in this project.
471 |
472 | ## Contributing
473 |
474 | Pull requests are welcome. `npm run test` and `npm run lint` before push.
475 |
--------------------------------------------------------------------------------
/demo/agenda.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/demo/agenda.gif
--------------------------------------------------------------------------------
/demo/calendar-list.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/demo/calendar-list.gif
--------------------------------------------------------------------------------
/demo/calendar.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/demo/calendar.gif
--------------------------------------------------------------------------------
/demo/custom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/demo/custom.png
--------------------------------------------------------------------------------
/demo/horizontal-calendar-list.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/demo/horizontal-calendar-list.gif
--------------------------------------------------------------------------------
/demo/loader.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/demo/loader.png
--------------------------------------------------------------------------------
/demo/marking1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/demo/marking1.png
--------------------------------------------------------------------------------
/demo/marking2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/demo/marking2.png
--------------------------------------------------------------------------------
/demo/marking3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/demo/marking3.png
--------------------------------------------------------------------------------
/demo/marking4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/demo/marking4.png
--------------------------------------------------------------------------------
/demo/marking5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/demo/marking5.png
--------------------------------------------------------------------------------
/demo/marking6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/demo/marking6.png
--------------------------------------------------------------------------------
/example/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react-native"]
3 | }
4 |
--------------------------------------------------------------------------------
/example/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/example/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | ; We fork some components by platform
3 | .*/*[.]android.js
4 |
5 | ; Ignore "BUCK" generated dirs
6 | /\.buckd/
7 |
8 | ; Ignore unexpected extra "@providesModule"
9 | .*/node_modules/.*/node_modules/fbjs/.*
10 |
11 | ; Ignore duplicate module providers
12 | ; For RN Apps installed via npm, "Libraries" folder is inside
13 | ; "node_modules/react-native" but in the source repo it is in the root
14 | .*/Libraries/react-native/React.js
15 | .*/Libraries/react-native/ReactNative.js
16 |
17 | [include]
18 |
19 | [libs]
20 | node_modules/react-native/Libraries/react-native/react-native-interface.js
21 | node_modules/react-native/flow
22 | flow/
23 |
24 | [options]
25 | emoji=true
26 |
27 | module.system=haste
28 |
29 | munge_underscores=true
30 |
31 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
32 |
33 | suppress_type=$FlowIssue
34 | suppress_type=$FlowFixMe
35 | suppress_type=$FixMe
36 |
37 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-9]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
38 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-9]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
39 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
40 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
41 |
42 | unsafe.enable_getters_and_setters=true
43 |
44 | [version]
45 | ^0.49.1
46 |
--------------------------------------------------------------------------------
/example/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/example/.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/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
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 |
44 | # fastlane
45 | #
46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47 | # screenshots whenever they are needed.
48 | # For more information about the recommended setup visit:
49 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
50 |
51 | fastlane/report.xml
52 | fastlane/Preview.html
53 | fastlane/screenshots
54 |
--------------------------------------------------------------------------------
/example/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/example/__tests__/index.android.js:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import React from 'react';
3 | import Index from '../index.android.js';
4 |
5 | // Note: test renderer must be required after react-native.
6 | import renderer from 'react-test-renderer';
7 |
8 | it('renders correctly', () => {
9 | const tree = renderer.create(
10 |
11 | );
12 | });
13 |
--------------------------------------------------------------------------------
/example/__tests__/index.ios.js:
--------------------------------------------------------------------------------
1 | import 'react-native';
2 | import React from 'react';
3 | import Index from '../index.ios.js';
4 |
5 | // Note: test renderer must be required after react-native.
6 | import renderer from 'react-test-renderer';
7 |
8 | it('renders correctly', () => {
9 | const tree = renderer.create(
10 |
11 | );
12 | });
13 |
--------------------------------------------------------------------------------
/example/android/app/BUCK:
--------------------------------------------------------------------------------
1 | # To learn about Buck see [Docs](https://buckbuild.com/).
2 | # To run your application with Buck:
3 | # - install Buck
4 | # - `npm start` - to start the packager
5 | # - `cd android`
6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8 | # - `buck install -r android/app` - compile, install and run application
9 | #
10 |
11 | lib_deps = []
12 |
13 | for jarfile in glob(['libs/*.jar']):
14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')]
15 | lib_deps.append(':' + name)
16 | prebuilt_jar(
17 | name = name,
18 | binary_jar = jarfile,
19 | )
20 |
21 | for aarfile in glob(['libs/*.aar']):
22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')]
23 | lib_deps.append(':' + name)
24 | android_prebuilt_aar(
25 | name = name,
26 | aar = aarfile,
27 | )
28 |
29 | android_library(
30 | name = "all-libs",
31 | exported_deps = lib_deps,
32 | )
33 |
34 | android_library(
35 | name = "app-code",
36 | srcs = glob([
37 | "src/main/java/**/*.java",
38 | ]),
39 | deps = [
40 | ":all-libs",
41 | ":build_config",
42 | ":res",
43 | ],
44 | )
45 |
46 | android_build_config(
47 | name = "build_config",
48 | package = "com.calendarsexample",
49 | )
50 |
51 | android_resource(
52 | name = "res",
53 | package = "com.calendarsexample",
54 | res = "src/main/res",
55 | )
56 |
57 | android_binary(
58 | name = "app",
59 | keystore = "//android/keystores:debug",
60 | manifest = "src/main/AndroidManifest.xml",
61 | package_type = "debug",
62 | deps = [
63 | ":app-code",
64 | ],
65 | )
66 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 |
3 | import com.android.build.OutputFile
4 |
5 | /**
6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
7 | * and bundleReleaseJsAndAssets).
8 | * These basically call `react-native bundle` with the correct arguments during the Android build
9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
10 | * bundle directly from the development server. Below you can see all the possible configurations
11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the
12 | * `apply from: "../../node_modules/react-native/react.gradle"` line.
13 | *
14 | * project.ext.react = [
15 | * // the name of the generated asset file containing your JS bundle
16 | * bundleAssetName: "index.android.bundle",
17 | *
18 | * // the entry file for bundle generation
19 | * entryFile: "index.android.js",
20 | *
21 | * // whether to bundle JS and assets in debug mode
22 | * bundleInDebug: false,
23 | *
24 | * // whether to bundle JS and assets in release mode
25 | * bundleInRelease: true,
26 | *
27 | * // whether to bundle JS and assets in another build variant (if configured).
28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
29 | * // The configuration property can be in the following formats
30 | * // 'bundleIn${productFlavor}${buildType}'
31 | * // 'bundleIn${buildType}'
32 | * // bundleInFreeDebug: true,
33 | * // bundleInPaidRelease: true,
34 | * // bundleInBeta: true,
35 | *
36 | * // whether to disable dev mode in custom build variants (by default only disabled in release)
37 | * // for example: to disable dev mode in the staging build type (if configured)
38 | * devDisabledInStaging: true,
39 | * // The configuration property can be in the following formats
40 | * // 'devDisabledIn${productFlavor}${buildType}'
41 | * // 'devDisabledIn${buildType}'
42 | *
43 | * // the root of your project, i.e. where "package.json" lives
44 | * root: "../../",
45 | *
46 | * // where to put the JS bundle asset in debug mode
47 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
48 | *
49 | * // where to put the JS bundle asset in release mode
50 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
51 | *
52 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
53 | * // require('./image.png')), in debug mode
54 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
55 | *
56 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
57 | * // require('./image.png')), in release mode
58 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
59 | *
60 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
61 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
62 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle
63 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
64 | * // for example, you might want to remove it from here.
65 | * inputExcludes: ["android/**", "ios/**"],
66 | *
67 | * // override which node gets called and with what additional arguments
68 | * nodeExecutableAndArgs: ["node"],
69 | *
70 | * // supply additional arguments to the packager
71 | * extraPackagerArgs: []
72 | * ]
73 | */
74 |
75 | apply from: "../../node_modules/react-native/react.gradle"
76 |
77 | /**
78 | * Set this to true to create two separate APKs instead of one:
79 | * - An APK that only works on ARM devices
80 | * - An APK that only works on x86 devices
81 | * The advantage is the size of the APK is reduced by about 4MB.
82 | * Upload all the APKs to the Play Store and people will download
83 | * the correct one based on the CPU architecture of their device.
84 | */
85 | def enableSeparateBuildPerCPUArchitecture = false
86 |
87 | /**
88 | * Run Proguard to shrink the Java bytecode in release builds.
89 | */
90 | def enableProguardInReleaseBuilds = false
91 |
92 | android {
93 | compileSdkVersion 25
94 | buildToolsVersion "25.0.1"
95 |
96 | defaultConfig {
97 | applicationId "com.calendarsexample"
98 | minSdkVersion 16
99 | targetSdkVersion 22
100 | versionCode 1
101 | versionName "1.0"
102 | ndk {
103 | abiFilters "armeabi-v7a", "x86"
104 | }
105 | }
106 | splits {
107 | abi {
108 | reset()
109 | enable enableSeparateBuildPerCPUArchitecture
110 | universalApk false // If true, also generate a universal APK
111 | include "armeabi-v7a", "x86"
112 | }
113 | }
114 | buildTypes {
115 | release {
116 | minifyEnabled enableProguardInReleaseBuilds
117 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
118 | }
119 | }
120 | // applicationVariants are e.g. debug, release
121 | applicationVariants.all { variant ->
122 | variant.outputs.each { output ->
123 | // For each separate APK per architecture, set a unique version code as described here:
124 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
125 | def versionCodes = ["armeabi-v7a":1, "x86":2]
126 | def abi = output.getFilter(OutputFile.ABI)
127 | if (abi != null) { // null for the universal-debug, universal-release variants
128 | output.versionCodeOverride =
129 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
130 | }
131 | }
132 | }
133 | }
134 |
135 | dependencies {
136 | compile fileTree(dir: "libs", include: ["*.jar"])
137 | compile "com.android.support:appcompat-v7:23.0.1"
138 | compile "com.facebook.react:react-native:+" // From node_modules
139 | compile project(':react-native-navigation')
140 | }
141 |
142 | // Run this once to be able to run the application with BUCK
143 | // puts all compile dependencies into folder libs for BUCK to use
144 | task copyDownloadableDepsToLibs(type: Copy) {
145 | from configurations.compile
146 | into 'libs'
147 | }
148 |
--------------------------------------------------------------------------------
/example/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Disabling obfuscation is useful if you collect stack traces from production crashes
20 | # (unless you are using a system that supports de-obfuscate the stack traces).
21 | -dontobfuscate
22 |
23 | # React Native
24 |
25 | # Keep our interfaces so they can be used by other ProGuard rules.
26 | # See http://sourceforge.net/p/proguard/bugs/466/
27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
30 |
31 | # Do not strip any method/class that is annotated with @DoNotStrip
32 | -keep @com.facebook.proguard.annotations.DoNotStrip class *
33 | -keep @com.facebook.common.internal.DoNotStrip class *
34 | -keepclassmembers class * {
35 | @com.facebook.proguard.annotations.DoNotStrip *;
36 | @com.facebook.common.internal.DoNotStrip *;
37 | }
38 |
39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
40 | void set*(***);
41 | *** get*();
42 | }
43 |
44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; }
46 | -keepclassmembers,includedescriptorclasses class * { native ; }
47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; }
48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; }
49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; }
50 |
51 | -dontwarn com.facebook.react.**
52 |
53 | # TextLayoutBuilder uses a non-public Android constructor within StaticLayout.
54 | # See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details.
55 | -dontwarn android.text.StaticLayout
56 |
57 | # okhttp
58 |
59 | -keepattributes Signature
60 | -keepattributes *Annotation*
61 | -keep class okhttp3.** { *; }
62 | -keep interface okhttp3.** { *; }
63 | -dontwarn okhttp3.**
64 |
65 | # okio
66 |
67 | -keep class sun.misc.Unsafe { *; }
68 | -dontwarn java.nio.file.*
69 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
70 | -dontwarn okio.**
71 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
19 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/calendarsexample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.calendarsexample;
2 |
3 | import com.reactnativenavigation.controllers.SplashActivity;
4 |
5 | public class MainActivity extends SplashActivity {
6 |
7 | /**
8 | * Returns the name of the main component registered from JavaScript.
9 | * This is used to schedule rendering of the component.
10 | */
11 | protected String getMainComponentName() {
12 | return "CalendarsExample";
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/calendarsexample/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.calendarsexample;
2 | import com.reactnativenavigation.NavigationApplication;
3 |
4 | import com.facebook.react.ReactPackage;
5 |
6 | import java.util.Arrays;
7 | import java.util.List;
8 |
9 | public class MainApplication extends NavigationApplication {
10 |
11 | @Override
12 | public boolean isDebug() {
13 | // Make sure you are using BuildConfig from your own application
14 | return BuildConfig.DEBUG;
15 | }
16 |
17 | protected List getPackages() {
18 | // Add additional packages you require here
19 | // No need to add RnnPackage and MainReactPackage
20 | return Arrays.asList(
21 | // eg. new VectorIconsPackage()
22 | );
23 | }
24 |
25 | @Override
26 | public List createAdditionalReactPackages() {
27 | return getPackages();
28 | }
29 | }
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CalendarsExample
3 |
4 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | mavenLocal()
18 | jcenter()
19 | maven {
20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
21 | url "$rootDir/../node_modules/react-native/android"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | android.useDeprecatedNdk=true
21 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/example/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
6 |
--------------------------------------------------------------------------------
/example/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/example/android/keystores/BUCK:
--------------------------------------------------------------------------------
1 | keystore(
2 | name = "debug",
3 | properties = "debug.keystore.properties",
4 | store = "debug.keystore",
5 | visibility = [
6 | "PUBLIC",
7 | ],
8 | )
9 |
--------------------------------------------------------------------------------
/example/android/keystores/debug.keystore.properties:
--------------------------------------------------------------------------------
1 | key.store=debug.keystore
2 | key.alias=androiddebugkey
3 | key.store.password=android
4 | key.alias.password=android
5 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'CalendarsExample'
2 |
3 | include ':react-native-navigation'
4 | project(':react-native-navigation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-navigation/android/app/')
5 | include ':app'
6 |
--------------------------------------------------------------------------------
/example/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CalendarsExample",
3 | "displayName": "CalendarsExample"
4 | }
--------------------------------------------------------------------------------
/example/index.android.js:
--------------------------------------------------------------------------------
1 | import App from './src/app';
2 |
--------------------------------------------------------------------------------
/example/index.ios.js:
--------------------------------------------------------------------------------
1 | import App from './src/app';
2 |
--------------------------------------------------------------------------------
/example/ios/CalendarsExample-tvOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UIViewControllerBasedStatusBarAppearance
38 |
39 | NSLocationWhenInUseUsageDescription
40 |
41 | NSAppTransportSecurity
42 |
43 |
44 | NSExceptionDomains
45 |
46 | localhost
47 |
48 | NSExceptionAllowsInsecureHTTPLoads
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/example/ios/CalendarsExample-tvOSTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/example/ios/CalendarsExample.xcodeproj/xcshareddata/xcschemes/CalendarsExample-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
58 |
59 |
61 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
79 |
80 |
81 |
82 |
92 |
94 |
100 |
101 |
102 |
103 |
104 |
105 |
111 |
113 |
119 |
120 |
121 |
122 |
124 |
125 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/example/ios/CalendarsExample.xcodeproj/xcshareddata/xcschemes/CalendarsExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
58 |
59 |
61 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
79 |
80 |
81 |
82 |
92 |
94 |
100 |
101 |
102 |
103 |
104 |
105 |
111 |
113 |
119 |
120 |
121 |
122 |
124 |
125 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/example/ios/CalendarsExample/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | @interface AppDelegate : UIResponder
13 |
14 | @property (nonatomic, strong) UIWindow *window;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/example/ios/CalendarsExample/AppDelegate.m:
--------------------------------------------------------------------------------
1 | #import "AppDelegate.h"
2 | #import
3 |
4 | // **********************************************
5 | // *** DON'T MISS: THE NEXT LINE IS IMPORTANT ***
6 | // **********************************************
7 | #import "RCCManager.h"
8 |
9 | // IMPORTANT: if you're getting an Xcode error that RCCManager.h isn't found, you've probably ran "npm install"
10 | // with npm ver 2. You'll need to "npm install" with npm 3 (see https://github.com/wix/react-native-navigation/issues/1)
11 |
12 | #import
13 |
14 | @implementation AppDelegate
15 |
16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
17 | {
18 | NSURL *jsCodeLocation;
19 | #ifdef DEBUG
20 | // jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
22 | #else
23 | jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
24 | #endif
25 |
26 |
27 | // **********************************************
28 | // *** DON'T MISS: THIS IS HOW WE BOOTSTRAP *****
29 | // **********************************************
30 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
31 | self.window.backgroundColor = [UIColor whiteColor];
32 | [[RCCManager sharedInstance] initBridgeWithBundleURL:jsCodeLocation launchOptions:launchOptions];
33 |
34 | /*
35 | // original RN bootstrap - remove this part
36 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
37 | moduleName:@"example"
38 | initialProperties:nil
39 | launchOptions:launchOptions];
40 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
41 | UIViewController *rootViewController = [UIViewController new];
42 | rootViewController.view = rootView;
43 | self.window.rootViewController = rootViewController;
44 | [self.window makeKeyAndVisible];
45 | */
46 |
47 |
48 | return YES;
49 | }
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/example/ios/CalendarsExample/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/example/ios/CalendarsExample/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/example/ios/CalendarsExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | CalendarsExample
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | NSAppTransportSecurity
28 |
29 | NSExceptionDomains
30 |
31 | localhost
32 |
33 | NSExceptionAllowsInsecureHTTPLoads
34 |
35 |
36 |
37 |
38 | NSLocationWhenInUseUsageDescription
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UIViewControllerBasedStatusBarAppearance
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/example/ios/CalendarsExample/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "AppDelegate.h"
13 |
14 | int main(int argc, char * argv[]) {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/example/ios/CalendarsExampleTests/CalendarsExampleTests.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 | #import
12 |
13 | #import
14 | #import
15 |
16 | #define TIMEOUT_SECONDS 600
17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
18 |
19 | @interface CalendarsExampleTests : XCTestCase
20 |
21 | @end
22 |
23 | @implementation CalendarsExampleTests
24 |
25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
26 | {
27 | if (test(view)) {
28 | return YES;
29 | }
30 | for (UIView *subview in [view subviews]) {
31 | if ([self findSubviewInView:subview matching:test]) {
32 | return YES;
33 | }
34 | }
35 | return NO;
36 | }
37 |
38 | - (void)testRendersWelcomeScreen
39 | {
40 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
42 | BOOL foundElement = NO;
43 |
44 | __block NSString *redboxError = nil;
45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
46 | if (level >= RCTLogLevelError) {
47 | redboxError = message;
48 | }
49 | });
50 |
51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
54 |
55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
57 | return YES;
58 | }
59 | return NO;
60 | }];
61 | }
62 |
63 | RCTSetLogFunction(RCTDefaultLogFunction);
64 |
65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
67 | }
68 |
69 |
70 | @end
71 |
--------------------------------------------------------------------------------
/example/ios/CalendarsExampleTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "CalendarsExample",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "start": "node node_modules/react-native/local-cli/cli.js start",
7 | "test": "jest"
8 | },
9 | "dependencies": {
10 | "react": "16.0.0-alpha.12",
11 | "react-native": "0.54.2",
12 | "react-native-calendars": "^1.17.5",
13 | "react-native-navigation": "^1.1.205"
14 | },
15 | "devDependencies": {
16 | "babel-jest": "20.0.3",
17 | "babel-preset-react-native": "3.0.1",
18 | "jest": "20.0.4",
19 | "react-test-renderer": "16.0.0-alpha.12"
20 | },
21 | "jest": {
22 | "preset": "react-native"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/example/src/app.js:
--------------------------------------------------------------------------------
1 | import {Navigation} from 'react-native-navigation';
2 | import {registerScreens} from './screens';
3 | registerScreens();
4 |
5 | // eslint-disable-next-line no-console
6 | console.ignoredYellowBox = ['Remote debugger'];
7 |
8 | /*
9 | import {LocaleConfig} from 'react-native-calendars';
10 |
11 | LocaleConfig.locales['fr'] = {
12 | monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'],
13 | monthNamesShort: ['Janv.','Févr.','Mars','Avril','Mai','Juin','Juil.','Août','Sept.','Oct.','Nov.','Déc.'],
14 | dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'],
15 | dayNamesShort: ['Dim.','Lun.','Mar.','Mer.','Jeu.','Ven.','Sam.']
16 | };
17 |
18 | LocaleConfig.defaultLocale = 'fr';
19 | */
20 |
21 | Navigation.startSingleScreenApp({
22 | screen: {
23 | screen: 'Menu',
24 | title: 'WixCal',
25 | },
26 | appStyle: {
27 | navBarBackgroundColor: '#00adf5',
28 | navBarTextColor: 'white',
29 | navBarButtonColor: '#ffffff',
30 | statusBarTextColorScheme: 'light',
31 | autoAdjustScrollViewInsets: true
32 | }
33 | });
--------------------------------------------------------------------------------
/example/src/screens/agenda.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import {
3 | Text,
4 | View,
5 | StyleSheet
6 | } from 'react-native';
7 | import {Agenda} from 'react-native-calendars';
8 |
9 | export default class AgendaScreen extends Component {
10 | constructor(props) {
11 | super(props);
12 | this.state = {
13 | items: {}
14 | };
15 | }
16 |
17 | render() {
18 | return (
19 | ({day ? day.day: 'item'})}
39 | />
40 | );
41 | }
42 |
43 | loadItems(day) {
44 | setTimeout(() => {
45 | for (let i = -15; i < 85; i++) {
46 | const time = day.timestamp + i * 24 * 60 * 60 * 1000;
47 | const strTime = this.timeToString(time);
48 | if (!this.state.items[strTime]) {
49 | this.state.items[strTime] = [];
50 | const numItems = Math.floor(Math.random() * 5);
51 | for (let j = 0; j < numItems; j++) {
52 | this.state.items[strTime].push({
53 | name: 'Item for ' + strTime,
54 | height: Math.max(50, Math.floor(Math.random() * 150))
55 | });
56 | }
57 | }
58 | }
59 | //console.log(this.state.items);
60 | const newItems = {};
61 | Object.keys(this.state.items).forEach(key => {newItems[key] = this.state.items[key];});
62 | this.setState({
63 | items: newItems
64 | });
65 | }, 1000);
66 | // console.log(`Load Items for ${day.year}-${day.month}`);
67 | }
68 |
69 | renderItem(item) {
70 | return (
71 | {item.name}
72 | );
73 | }
74 |
75 | renderEmptyDate() {
76 | return (
77 | This is empty date!
78 | );
79 | }
80 |
81 | rowHasChanged(r1, r2) {
82 | return r1.name !== r2.name;
83 | }
84 |
85 | timeToString(time) {
86 | const date = new Date(time);
87 | return date.toISOString().split('T')[0];
88 | }
89 | }
90 |
91 | const styles = StyleSheet.create({
92 | item: {
93 | backgroundColor: 'white',
94 | flex: 1,
95 | borderRadius: 5,
96 | padding: 10,
97 | marginRight: 10,
98 | marginTop: 17
99 | },
100 | emptyDate: {
101 | height: 15,
102 | flex:1,
103 | paddingTop: 30
104 | }
105 | });
106 |
--------------------------------------------------------------------------------
/example/src/screens/calendars.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {
3 | Text,
4 | StyleSheet,
5 | ScrollView,
6 | View
7 | } from 'react-native';
8 | import {Calendar} from 'react-native-calendars';
9 |
10 | export default class CalendarsScreen extends Component {
11 | constructor(props) {
12 | super(props);
13 | this.state = {};
14 | this.onDayPress = this.onDayPress.bind(this);
15 | }
16 |
17 | render() {
18 | return (
19 |
20 | Calendar with selectable date and arrows
21 |
27 | Calendar with marked dates and hidden arrows
28 |
44 | Calendar with custom day component
45 | {
48 | return ({date.day});
49 | }}
50 | />
51 | Calendar with period marking and spinner
52 |
88 | Calendar with multi-dot marking
89 |
99 | Calendar with multi-period marking
100 |
128 | Calendar with week numbers
129 |
136 | Custom calendar with custom marking type
137 |
252 |
253 | );
254 | }
255 |
256 | onDayPress(day) {
257 | this.setState({
258 | selected: day.dateString
259 | });
260 | }
261 | }
262 |
263 | const styles = StyleSheet.create({
264 | calendar: {
265 | borderTopWidth: 1,
266 | paddingTop: 5,
267 | borderBottomWidth: 1,
268 | borderColor: '#eee',
269 | height: 350
270 | },
271 | text: {
272 | textAlign: 'center',
273 | borderColor: '#bbb',
274 | padding: 10,
275 | backgroundColor: '#eee'
276 | },
277 | container: {
278 | flex: 1,
279 | backgroundColor: 'gray'
280 | }
281 | });
282 |
--------------------------------------------------------------------------------
/example/src/screens/calendarsList.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 |
3 | import {CalendarList} from 'react-native-calendars';
4 |
5 | export default class CalendarsList extends Component {
6 | constructor(props) {
7 | super(props);
8 | }
9 |
10 | render() {
11 | return (
12 |
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/example/src/screens/horizontalCalendarList.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 |
3 | import {CalendarList} from 'react-native-calendars';
4 | import {View} from 'react-native';
5 |
6 | export default class HorizontalCalendarList extends Component {
7 | constructor(props) {
8 | super(props);
9 | }
10 |
11 | render() {
12 | return (
13 |
14 |
22 |
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/example/src/screens/index.js:
--------------------------------------------------------------------------------
1 | import {Navigation} from 'react-native-navigation';
2 |
3 | import MenuScreen from './menu';
4 | import CalendarsScreen from './calendars';
5 | import AgendaScreen from './agenda';
6 | import CalendarsList from './calendarsList';
7 | import HorizontalCalendarList from './horizontalCalendarList';
8 |
9 | export function registerScreens() {
10 | Navigation.registerComponent('Menu', () => MenuScreen);
11 | Navigation.registerComponent('Calendars', () => CalendarsScreen);
12 | Navigation.registerComponent('Agenda', () => AgendaScreen);
13 | Navigation.registerComponent('CalendarsList', () => CalendarsList);
14 | Navigation.registerComponent('HorizontalCalendarList', () => HorizontalCalendarList);
15 | }
16 |
--------------------------------------------------------------------------------
/example/src/screens/menu.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {
3 | Text,
4 | View,
5 | TouchableOpacity,
6 | StyleSheet,
7 | } from 'react-native';
8 |
9 | export default class MenuScreen extends Component {
10 |
11 | render() {
12 | return (
13 |
14 |
15 | Calendars
16 |
17 |
18 | Calendar List
19 |
20 |
21 | Horizontal Calendar List
22 |
23 |
24 | Agenda
25 |
26 |
27 | );
28 | }
29 |
30 | onCalendarsPress() {
31 | this.props.navigator.push({
32 | screen: 'Calendars',
33 | title: 'Calendars'
34 | });
35 | }
36 |
37 | onCalendarListPress() {
38 | this.props.navigator.push({
39 | screen: 'CalendarsList',
40 | title: 'Calendar List'
41 | });
42 | }
43 |
44 | onHorizontalCalendarListPress() {
45 | this.props.navigator.push({
46 | screen: 'HorizontalCalendarList',
47 | title: 'Horizontal Calendars List'
48 | });
49 | }
50 |
51 | onAgendaPress() {
52 | this.props.navigator.push({
53 | screen: 'Agenda',
54 | title: 'Agenda'
55 | });
56 | }
57 | }
58 |
59 | const styles = StyleSheet.create({
60 | menu: {
61 | height: 50,
62 | justifyContent: 'center',
63 | paddingLeft: 15,
64 | borderBottomWidth: 1
65 | },
66 | menuText: {
67 | fontSize: 18
68 | }
69 | });
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-calendars",
3 | "version": "1.20.0",
4 | "main": "src/index.js",
5 | "description": "React Native Calendar Components",
6 | "scripts": {
7 | "test": "jasmine src/*.spec.js && npm run lint",
8 | "lint": "eslint src/ example/src"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/wix/react-native-calendars"
13 | },
14 | "publishConfig": {
15 | "registry": "https://registry.npmjs.org/"
16 | },
17 | "author": "Wix.com",
18 | "license": "MIT",
19 | "dependencies": {
20 | "lodash.get": "^4.4.2",
21 | "lodash.isequal": "^4.5.0",
22 | "prop-types": "^15.5.10",
23 | "xdate": "^0.8.0"
24 | },
25 | "devDependencies": {
26 | "babel-eslint": "^7.2.3",
27 | "eslint": "^3.19.0",
28 | "eslint-plugin-react": "^7.0.0",
29 | "jasmine": "^2.5.2",
30 | "react": "16.0.0-alpha.12",
31 | "react-native": "0.47.2"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | com.wixpress.hotels
5 | wix-react-native-calendar
6 | 1.0.0-SNAPSHOT
7 | pom
8 | Wix React Native Calendar
9 | WiX React Native Calendar
10 |
11 |
12 | com.wixpress.common
13 | wix-master-parent
14 | 100.0.0-SNAPSHOT
15 |
16 |
17 |
18 |
19 | tautvilas@wix.com
20 | Tautvilas Mecinskas
21 | tautvilas@wix.com
22 | Wix
23 | http://www.wix.com
24 |
25 | owner
26 |
27 | -2
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/spec/runner.js:
--------------------------------------------------------------------------------
1 | import Jasmine from 'jasmine';
2 | import path from 'path';
3 |
4 | var jasmine = new Jasmine();
5 | jasmine.loadConfigFile(path.resolve(__dirname, 'support', 'jasmine.json'));
6 | jasmine.execute();
7 |
--------------------------------------------------------------------------------
/spec/support/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": "src",
3 | "spec_files": [
4 | "*.spec.js"
5 | ],
6 | "stopSpecOnExpectationFailure": false,
7 | "random": false
8 | }
9 |
--------------------------------------------------------------------------------
/src/agenda/img/knob@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/src/agenda/img/knob@2x.png
--------------------------------------------------------------------------------
/src/agenda/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {
3 | Text,
4 | View,
5 | Dimensions,
6 | Animated,
7 | ViewPropTypes,
8 | } from 'react-native';
9 | import PropTypes from 'prop-types';
10 | import XDate from 'xdate';
11 |
12 | import {parseDate, xdateToData} from '../interface';
13 | import dateutils from '../dateutils';
14 | import CalendarList from '../calendar-list';
15 | import ReservationsList from './reservation-list';
16 | import styleConstructor from './style';
17 | import { VelocityTracker } from '../input';
18 |
19 | const HEADER_HEIGHT = 104;
20 | const KNOB_HEIGHT = 24;
21 |
22 | //Fallback when RN version is < 0.44
23 | const viewPropTypes = ViewPropTypes || View.propTypes;
24 |
25 | export default class AgendaView extends Component {
26 | static propTypes = {
27 | // Specify theme properties to override specific styles for calendar parts. Default = {}
28 | theme: PropTypes.object,
29 |
30 | // agenda container style
31 | style: viewPropTypes.style,
32 |
33 | // the list of items that have to be displayed in agenda. If you want to render item as empty date
34 | // the value of date key has to be an empty array []. If there exists no value for date key it is
35 | // considered that the date in question is not yet loaded
36 | items: PropTypes.object,
37 |
38 | // callback that gets called when items for a certain month should be loaded (month became visible)
39 | loadItemsForMonth: PropTypes.func,
40 | // callback that fires when the calendar is opened or closed
41 | onCalendarToggled: PropTypes.func,
42 | // callback that gets called on day press
43 | onDayPress: PropTypes.func,
44 | // callback that gets called when day changes while scrolling agenda list
45 | onDaychange: PropTypes.func,
46 | // specify how each item should be rendered in agenda
47 | renderItem: PropTypes.func,
48 | // specify how each date should be rendered. day can be undefined if the item is not first in that day.
49 | renderDay: PropTypes.func,
50 | // specify how agenda knob should look like
51 | renderKnob: PropTypes.func,
52 | // specify how empty date content with no items should be rendered
53 | renderEmptyDay: PropTypes.func,
54 | // specify what should be rendered instead of ActivityIndicator
55 | renderEmptyData: PropTypes.func,
56 | // specify your item comparison function for increased performance
57 | rowHasChanged: PropTypes.func,
58 |
59 | // Max amount of months allowed to scroll to the past. Default = 50
60 | pastScrollRange: PropTypes.number,
61 |
62 | // Max amount of months allowed to scroll to the future. Default = 50
63 | futureScrollRange: PropTypes.number,
64 |
65 | // initially selected day
66 | selected: PropTypes.any,
67 | // Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
68 | minDate: PropTypes.any,
69 | // Maximum date that can be selected, dates after maxDate will be grayed out. Default = undefined
70 | maxDate: PropTypes.any,
71 |
72 | // If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
73 | firstDay: PropTypes.number,
74 |
75 | // Collection of dates that have to be marked. Default = items
76 | markedDates: PropTypes.object,
77 | // Optional marking type if custom markedDates are provided
78 | markingType: PropTypes.string,
79 |
80 | // Hide knob button. Default = false
81 | hideKnob: PropTypes.bool,
82 | // Month format in calendar title. Formatting values: http://arshaw.com/xdate/#Formatting
83 | monthFormat: PropTypes.string,
84 | // A RefreshControl component, used to provide pull-to-refresh functionality for the ScrollView.
85 | refreshControl: PropTypes.element,
86 | // If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make sure to also set the refreshing prop correctly.
87 | onRefresh: PropTypes.func,
88 | // Set this true while waiting for new data from a refresh.
89 | refreshing: PropTypes.bool,
90 | // Display loading indicador. Default = false
91 | displayLoadingIndicator: PropTypes.bool,
92 | };
93 |
94 | constructor(props) {
95 | super(props);
96 | this.styles = styleConstructor(props.theme);
97 | const windowSize = Dimensions.get('window');
98 | this.viewHeight = windowSize.height;
99 | this.viewWidth = windowSize.width;
100 | this.scrollTimeout = undefined;
101 | this.headerState = 'idle';
102 | this.state = {
103 | scrollY: new Animated.Value(0),
104 | calendarIsReady: false,
105 | calendarScrollable: false,
106 | firstResevationLoad: false,
107 | selectedDay: parseDate(this.props.selected) || XDate(true),
108 | topDay: parseDate(this.props.selected) || XDate(true),
109 | };
110 | this.currentMonth = this.state.selectedDay.clone();
111 | this.onLayout = this.onLayout.bind(this);
112 | this.onScrollPadLayout = this.onScrollPadLayout.bind(this);
113 | this.onTouchStart = this.onTouchStart.bind(this);
114 | this.onTouchEnd = this.onTouchEnd.bind(this);
115 | this.onStartDrag = this.onStartDrag.bind(this);
116 | this.onSnapAfterDrag = this.onSnapAfterDrag.bind(this);
117 | this.generateMarkings = this.generateMarkings.bind(this);
118 | this.knobTracker = new VelocityTracker();
119 | this.state.scrollY.addListener(({value}) => this.knobTracker.add(value));
120 | }
121 |
122 | calendarOffset() {
123 | return 90 - (this.viewHeight / 2);
124 | }
125 |
126 | initialScrollPadPosition() {
127 | return Math.max(0, this.viewHeight - HEADER_HEIGHT);
128 | }
129 |
130 | setScrollPadPosition(y, animated) {
131 | this.scrollPad._component.scrollTo({x: 0, y, animated});
132 | }
133 |
134 | onScrollPadLayout() {
135 | // When user touches knob, the actual component that receives touch events is a ScrollView.
136 | // It needs to be scrolled to the bottom, so that when user moves finger downwards,
137 | // scroll position actually changes (it would stay at 0, when scrolled to the top).
138 | this.setScrollPadPosition(this.initialScrollPadPosition(), false);
139 | // delay rendering calendar in full height because otherwise it still flickers sometimes
140 | setTimeout(() => this.setState({calendarIsReady: true}), 0);
141 | }
142 |
143 | onLayout(event) {
144 | this.viewHeight = event.nativeEvent.layout.height;
145 | this.viewWidth = event.nativeEvent.layout.width;
146 | this.forceUpdate();
147 | }
148 |
149 | onTouchStart() {
150 | this.headerState = 'touched';
151 | if (this.knob) {
152 | this.knob.setNativeProps({style: { opacity: 0.5 }});
153 | }
154 | }
155 |
156 | onTouchEnd() {
157 | if (this.knob) {
158 | this.knob.setNativeProps({style: { opacity: 1 }});
159 | }
160 |
161 | if (this.headerState === 'touched') {
162 | this.setScrollPadPosition(0, true);
163 | this.enableCalendarScrolling();
164 | }
165 | this.headerState = 'idle';
166 | }
167 |
168 | onStartDrag() {
169 | this.headerState = 'dragged';
170 | this.knobTracker.reset();
171 | }
172 |
173 | onSnapAfterDrag(e) {
174 | // on Android onTouchEnd is not called if dragging was started
175 | this.onTouchEnd();
176 | const currentY = e.nativeEvent.contentOffset.y;
177 | this.knobTracker.add(currentY);
178 | const projectedY = currentY + this.knobTracker.estimateSpeed() * 250/*ms*/;
179 | const maxY = this.initialScrollPadPosition();
180 | const snapY = (projectedY > maxY / 2) ? maxY : 0;
181 | this.setScrollPadPosition(snapY, true);
182 | if (snapY === 0) {
183 | this.enableCalendarScrolling();
184 | }
185 | }
186 |
187 | onVisibleMonthsChange(months) {
188 | if (this.props.items && !this.state.firstResevationLoad) {
189 | clearTimeout(this.scrollTimeout);
190 | this.scrollTimeout = setTimeout(() => {
191 | if (this.props.loadItemsForMonth && this._isMounted) {
192 | this.props.loadItemsForMonth(months[0]);
193 | }
194 | }, 200);
195 | }
196 | }
197 |
198 | loadReservations(props) {
199 | if ((!props.items || !Object.keys(props.items).length) && !this.state.firstResevationLoad) {
200 | this.setState({
201 | firstResevationLoad: true
202 | }, () => {
203 | if (this.props.loadItemsForMonth) {
204 | this.props.loadItemsForMonth(xdateToData(this.state.selectedDay));
205 | }
206 | });
207 | }
208 | }
209 |
210 | componentWillMount() {
211 | this._isMounted = true;
212 | this.loadReservations(this.props);
213 | }
214 |
215 | componentWillUnmount() {
216 | this._isMounted = false;
217 | }
218 |
219 | componentWillReceiveProps(props) {
220 | if (props.items) {
221 | this.setState({
222 | firstResevationLoad: false
223 | });
224 | } else {
225 | this.loadReservations(props);
226 | }
227 | }
228 |
229 | enableCalendarScrolling() {
230 | this.setState({
231 | calendarScrollable: true
232 | });
233 | if (this.props.onCalendarToggled) {
234 | this.props.onCalendarToggled(true);
235 | }
236 | // Enlarge calendarOffset here as a workaround on iOS to force repaint.
237 | // Otherwise the month after current one or before current one remains invisible.
238 | // The problem is caused by overflow: 'hidden' style, which we need for dragging
239 | // to be performant.
240 | // Another working solution for this bug would be to set removeClippedSubviews={false}
241 | // in CalendarList listView, but that might impact performance when scrolling
242 | // month list in expanded CalendarList.
243 | // Further info https://github.com/facebook/react-native/issues/1831
244 | this.calendar.scrollToDay(this.state.selectedDay, this.calendarOffset() + 1, true);
245 | }
246 |
247 | _chooseDayFromCalendar(d) {
248 | this.chooseDay(d, !this.state.calendarScrollable);
249 | }
250 |
251 | chooseDay(d, optimisticScroll) {
252 | const day = parseDate(d);
253 | this.setState({
254 | calendarScrollable: false,
255 | selectedDay: day.clone()
256 | });
257 | if (this.props.onCalendarToggled) {
258 | this.props.onCalendarToggled(false);
259 | }
260 | if (!optimisticScroll) {
261 | this.setState({
262 | topDay: day.clone()
263 | });
264 | }
265 | this.setScrollPadPosition(this.initialScrollPadPosition(), true);
266 | this.calendar.scrollToDay(day, this.calendarOffset(), true);
267 | if (this.props.loadItemsForMonth) {
268 | this.props.loadItemsForMonth(xdateToData(day));
269 | }
270 | if (this.props.onDayPress) {
271 | this.props.onDayPress(xdateToData(day));
272 | }
273 | }
274 |
275 | renderReservations() {
276 | return (
277 | {}}
291 | ref={(c) => this.list = c}
292 | theme={this.props.theme}
293 | />
294 | );
295 | }
296 |
297 | onDayChange(day) {
298 | const newDate = parseDate(day);
299 | const withAnimation = dateutils.sameMonth(newDate, this.state.selectedDay);
300 | this.calendar.scrollToDay(day, this.calendarOffset(), withAnimation);
301 | this.setState({
302 | selectedDay: parseDate(day)
303 | });
304 |
305 | if (this.props.onDayChange) {
306 | this.props.onDayChange(xdateToData(newDate));
307 | }
308 | }
309 |
310 | generateMarkings() {
311 | let markings = this.props.markedDates;
312 | if (!markings) {
313 | markings = {};
314 | Object.keys(this.props.items || {}).forEach(key => {
315 | if (this.props.items[key] && this.props.items[key].length) {
316 | markings[key] = {marked: true};
317 | }
318 | });
319 | }
320 | const key = this.state.selectedDay.toString('yyyy-MM-dd');
321 | return {...markings, [key]: {...(markings[key] || {}), ...{selected: true}}};
322 | }
323 |
324 | render() {
325 | const agendaHeight = Math.max(0, this.viewHeight - HEADER_HEIGHT);
326 | const weekDaysNames = dateutils.weekDayNames(this.props.firstDay);
327 | const weekdaysStyle = [this.styles.weekdays, {
328 | opacity: this.state.scrollY.interpolate({
329 | inputRange: [agendaHeight - HEADER_HEIGHT, agendaHeight],
330 | outputRange: [0, 1],
331 | extrapolate: 'clamp',
332 | }),
333 | transform: [{ translateY: this.state.scrollY.interpolate({
334 | inputRange: [Math.max(0, agendaHeight - HEADER_HEIGHT), agendaHeight],
335 | outputRange: [-HEADER_HEIGHT, 0],
336 | extrapolate: 'clamp',
337 | })}]
338 | }];
339 |
340 | const headerTranslate = this.state.scrollY.interpolate({
341 | inputRange: [0, agendaHeight],
342 | outputRange: [agendaHeight, 0],
343 | extrapolate: 'clamp',
344 | });
345 |
346 | const contentTranslate = this.state.scrollY.interpolate({
347 | inputRange: [0, agendaHeight],
348 | outputRange: [0, agendaHeight/2],
349 | extrapolate: 'clamp',
350 | });
351 |
352 | const headerStyle = [
353 | this.styles.header,
354 | { bottom: agendaHeight, transform: [{ translateY: headerTranslate }] },
355 | ];
356 |
357 | if (!this.state.calendarIsReady) {
358 | // limit header height until everything is setup for calendar dragging
359 | headerStyle.push({height: 0});
360 | // fill header with appStyle.calendarBackground background to reduce flickering
361 | weekdaysStyle.push({height: HEADER_HEIGHT});
362 | }
363 |
364 | const shouldAllowDragging = !this.props.hideKnob && !this.state.calendarScrollable;
365 | const scrollPadPosition = (shouldAllowDragging ? HEADER_HEIGHT : 0) - KNOB_HEIGHT;
366 |
367 | const scrollPadStyle = {
368 | position: 'absolute',
369 | width: 80,
370 | height: KNOB_HEIGHT,
371 | top: scrollPadPosition,
372 | left: (this.viewWidth - 80) / 2,
373 | };
374 |
375 | let knob = ();
376 |
377 | if (!this.props.hideKnob) {
378 | const knobView = this.props.renderKnob ? this.props.renderKnob() : ();
379 | knob = this.state.calendarScrollable ? null : (
380 |
381 | this.knob = c}>{knobView}
382 |
383 | );
384 | }
385 |
386 | return (
387 |
388 |
389 | {this.renderReservations()}
390 |
391 |
392 |
393 | {
395 | this.calendar.scrollToDay(this.state.selectedDay.clone(), this.calendarOffset(), false);
396 | }}
397 | calendarWidth={this.viewWidth}
398 | theme={this.props.theme}
399 | onVisibleMonthsChange={this.onVisibleMonthsChange.bind(this)}
400 | ref={(c) => this.calendar = c}
401 | minDate={this.props.minDate}
402 | maxDate={this.props.maxDate}
403 | current={this.currentMonth}
404 | markedDates={this.generateMarkings()}
405 | markingType={this.props.markingType}
406 | removeClippedSubviews={this.props.removeClippedSubviews}
407 | onDayPress={this._chooseDayFromCalendar.bind(this)}
408 | scrollingEnabled={this.state.calendarScrollable}
409 | hideExtraDays={this.state.calendarScrollable}
410 | firstDay={this.props.firstDay}
411 | monthFormat={this.props.monthFormat}
412 | pastScrollRange={this.props.pastScrollRange}
413 | futureScrollRange={this.props.futureScrollRange}
414 | dayComponent={this.props.dayComponent}
415 | disabledByDefault={this.props.disabledByDefault}
416 | displayLoadingIndicator={this.props.displayLoadingIndicator}
417 | showWeekNumbers={this.props.showWeekNumbers}
418 | />
419 |
420 | {knob}
421 |
422 |
423 | {this.props.showWeekNumbers && }
424 | {weekDaysNames.map((day) => (
425 | {day}
426 | ))}
427 |
428 | this.scrollPad = c}
430 | overScrollMode='never'
431 | showsHorizontalScrollIndicator={false}
432 | showsVerticalScrollIndicator={false}
433 | style={scrollPadStyle}
434 | scrollEventThrottle={1}
435 | scrollsToTop={false}
436 | onTouchStart={this.onTouchStart}
437 | onTouchEnd={this.onTouchEnd}
438 | onScrollBeginDrag={this.onStartDrag}
439 | onScrollEndDrag={this.onSnapAfterDrag}
440 | onScroll={Animated.event(
441 | [{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }],
442 | { useNativeDriver: true },
443 | )}
444 | >
445 |
446 |
447 |
448 | );
449 | }
450 | }
451 |
--------------------------------------------------------------------------------
/src/agenda/platform-style.ios.js:
--------------------------------------------------------------------------------
1 | export default function platformStyles(appStyle) {
2 | return {
3 | knob: {
4 | width: 38,
5 | height: 7,
6 | marginTop: 10,
7 | borderRadius: 3,
8 | backgroundColor: appStyle.agendaKnobColor
9 | },
10 | weekdays: {
11 | position: 'absolute',
12 | left: 0,
13 | right: 0,
14 | top: 0,
15 | flexDirection: 'row',
16 | justifyContent: 'space-around',
17 | marginLeft: 15,
18 | marginRight: 15,
19 | paddingTop: 15,
20 | paddingBottom: 7,
21 | backgroundColor: appStyle.calendarBackground
22 | },
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/src/agenda/platform-style.js:
--------------------------------------------------------------------------------
1 | export default function platformStyles(appStyle) {
2 | return {
3 | knob: {
4 | width: 38,
5 | height: 7,
6 | marginTop: 10,
7 | borderRadius: 3,
8 | backgroundColor: appStyle.agendaKnobColor
9 | },
10 | weekdays: {
11 | position: 'absolute',
12 | left: 0,
13 | right: 0,
14 | top: 0,
15 | flexDirection: 'row',
16 | justifyContent: 'space-between',
17 | paddingLeft: 24,
18 | paddingRight: 24,
19 | paddingTop: 15,
20 | paddingBottom: 7,
21 | backgroundColor: appStyle.calendarBackground
22 | },
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/src/agenda/reservation-list/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {
3 | FlatList,
4 | ActivityIndicator,
5 | View
6 | } from 'react-native';
7 | import Reservation from './reservation';
8 | import PropTypes from 'prop-types';
9 | import XDate from 'xdate';
10 |
11 | import dateutils from '../../dateutils';
12 | import styleConstructor from './style';
13 |
14 | class ReactComp extends Component {
15 | static propTypes = {
16 | // specify your item comparison function for increased performance
17 | rowHasChanged: PropTypes.func,
18 | // specify how each item should be rendered in agenda
19 | renderItem: PropTypes.func,
20 | // specify how each date should be rendered. day can be undefined if the item is not first in that day.
21 | renderDay: PropTypes.func,
22 | // specify how empty date content with no items should be rendered
23 | renderEmptyDate: PropTypes.func,
24 | // callback that gets called when day changes while scrolling agenda list
25 | onDayChange: PropTypes.func,
26 | // onScroll ListView event
27 | onScroll: PropTypes.func,
28 | // the list of items that have to be displayed in agenda. If you want to render item as empty date
29 | // the value of date key kas to be an empty array []. If there exists no value for date key it is
30 | // considered that the date in question is not yet loaded
31 | reservations: PropTypes.object,
32 |
33 | selectedDay: PropTypes.instanceOf(XDate),
34 | topDay: PropTypes.instanceOf(XDate),
35 | refreshControl: PropTypes.element,
36 | refreshing: PropTypes.bool,
37 | onRefresh: PropTypes.func,
38 | };
39 |
40 | constructor(props) {
41 | super(props);
42 | this.styles = styleConstructor(props.theme);
43 | this.state = {
44 | reservations: []
45 | };
46 | this.heights=[];
47 | this.selectedDay = this.props.selectedDay;
48 | this.scrollOver = true;
49 | }
50 |
51 | componentWillMount() {
52 | this.updateDataSource(this.getReservations(this.props).reservations);
53 | }
54 |
55 | updateDataSource(reservations) {
56 | this.setState({
57 | reservations
58 | });
59 | }
60 |
61 | updateReservations(props) {
62 | const reservations = this.getReservations(props);
63 | if (this.list && !dateutils.sameDate(props.selectedDay, this.selectedDay)) {
64 | let scrollPosition = 0;
65 | for (let i = 0; i < reservations.scrollPosition; i++) {
66 | scrollPosition += this.heights[i] || 0;
67 | }
68 | this.scrollOver = false;
69 | this.list.scrollToOffset({offset: scrollPosition, animated: true});
70 | }
71 | this.selectedDay = props.selectedDay;
72 | this.updateDataSource(reservations.reservations);
73 | }
74 |
75 | componentWillReceiveProps(props) {
76 | if (!dateutils.sameDate(props.topDay, this.props.topDay)) {
77 | this.setState({
78 | reservations: []
79 | }, () => {
80 | this.updateReservations(props);
81 | });
82 | } else {
83 | this.updateReservations(props);
84 | }
85 | }
86 |
87 | onScroll(event) {
88 | const yOffset = event.nativeEvent.contentOffset.y;
89 | this.props.onScroll(yOffset);
90 | let topRowOffset = 0;
91 | let topRow;
92 | for (topRow = 0; topRow < this.heights.length; topRow++) {
93 | if (topRowOffset + this.heights[topRow] / 2 >= yOffset) {
94 | break;
95 | }
96 | topRowOffset += this.heights[topRow];
97 | }
98 | const row = this.state.reservations[topRow];
99 | if (!row) return;
100 | const day = row.day;
101 | const sameDate = dateutils.sameDate(day, this.selectedDay);
102 | if (!sameDate && this.scrollOver) {
103 | this.selectedDay = day.clone();
104 | this.props.onDayChange(day.clone());
105 | }
106 | }
107 |
108 | onRowLayoutChange(ind, event) {
109 | this.heights[ind] = event.nativeEvent.layout.height;
110 | }
111 |
112 | renderRow({item, index}) {
113 | return (
114 |
115 |
123 |
124 | );
125 | }
126 |
127 | getReservationsForDay(iterator, props) {
128 | const day = iterator.clone();
129 | const res = props.reservations[day.toString('yyyy-MM-dd')];
130 | if (res && res.length) {
131 | return res.map((reservation, i) => {
132 | return {
133 | reservation,
134 | date: i ? false : day,
135 | day
136 | };
137 | });
138 | } else if (res) {
139 | return [{
140 | date: iterator.clone(),
141 | day
142 | }];
143 | } else {
144 | return false;
145 | }
146 | }
147 |
148 | onListTouch() {
149 | this.scrollOver = true;
150 | }
151 |
152 | getReservations(props) {
153 | if (!props.reservations || !props.selectedDay) {
154 | return {reservations: [], scrollPosition: 0};
155 | }
156 | let reservations = [];
157 | if (this.state.reservations && this.state.reservations.length) {
158 | const iterator = this.state.reservations[0].day.clone();
159 | while (iterator.getTime() < props.selectedDay.getTime()) {
160 | const res = this.getReservationsForDay(iterator, props);
161 | if (!res) {
162 | reservations = [];
163 | break;
164 | } else {
165 | reservations = reservations.concat(res);
166 | }
167 | iterator.addDays(1);
168 | }
169 | }
170 | const scrollPosition = reservations.length;
171 | const iterator = props.selectedDay.clone();
172 | for (let i = 0; i < 31; i++) {
173 | const res = this.getReservationsForDay(iterator, props);
174 | if (res) {
175 | reservations = reservations.concat(res);
176 | }
177 | iterator.addDays(1);
178 | }
179 |
180 | return {reservations, scrollPosition};
181 | }
182 |
183 | render() {
184 | if (!this.props.reservations || !this.props.reservations[this.props.selectedDay.toString('yyyy-MM-dd')]) {
185 | if (this.props.renderEmptyData) {
186 | return this.props.renderEmptyData();
187 | }
188 | return ();
189 | }
190 | return (
191 | this.list = c}
193 | style={this.props.style}
194 | contentContainerStyle={this.styles.content}
195 | renderItem={this.renderRow.bind(this)}
196 | data={this.state.reservations}
197 | onScroll={this.onScroll.bind(this)}
198 | showsVerticalScrollIndicator={false}
199 | scrollEventThrottle={200}
200 | onMoveShouldSetResponderCapture={() => {this.onListTouch(); return false;}}
201 | keyExtractor={(item, index) => String(index)}
202 | refreshControl={this.props.refreshControl}
203 | refreshing={this.props.refreshing || false}
204 | onRefresh={this.props.onRefresh}
205 | />
206 | );
207 | }
208 | }
209 |
210 | export default ReactComp;
211 |
--------------------------------------------------------------------------------
/src/agenda/reservation-list/reservation.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {View, Text} from 'react-native';
3 | import {xdateToData} from '../../interface';
4 | import XDate from 'xdate';
5 | import dateutils from '../../dateutils';
6 | import styleConstructor from './style';
7 |
8 | class ReservationListItem extends Component {
9 | constructor(props) {
10 | super(props);
11 | this.styles = styleConstructor(props.theme);
12 | }
13 |
14 | shouldComponentUpdate(nextProps) {
15 | const r1 = this.props.item;
16 | const r2 = nextProps.item;
17 | let changed = true;
18 | if (!r1 && !r2) {
19 | changed = false;
20 | } else if (r1 && r2) {
21 | if (r1.day.getTime() !== r2.day.getTime()) {
22 | changed = true;
23 | } else if (!r1.reservation && !r2.reservation) {
24 | changed = false;
25 | } else if (r1.reservation && r2.reservation) {
26 | if ((!r1.date && !r2.date) || (r1.date && r2.date)) {
27 | changed = this.props.rowHasChanged(r1.reservation, r2.reservation);
28 | }
29 | }
30 | }
31 | return changed;
32 | }
33 |
34 | renderDate(date, item) {
35 | if (this.props.renderDay) {
36 | return this.props.renderDay(date ? xdateToData(date) : undefined, item);
37 | }
38 | const today = dateutils.sameDate(date, XDate()) ? this.styles.today : undefined;
39 | if (date) {
40 | return (
41 |
42 | {date.getDate()}
43 | {XDate.locales[XDate.defaultLocale].dayNamesShort[date.getDay()]}
44 |
45 | );
46 | } else {
47 | return (
48 |
49 | );
50 | }
51 | }
52 |
53 | render() {
54 | const {reservation, date} = this.props.item;
55 | let content;
56 | if (reservation) {
57 | const firstItem = date ? true : false;
58 | content = this.props.renderItem(reservation, firstItem);
59 | } else {
60 | content = this.props.renderEmptyDate(date);
61 | }
62 | return (
63 |
64 | {this.renderDate(date, reservation)}
65 |
66 | {content}
67 |
68 |
69 | );
70 | }
71 | }
72 |
73 | export default ReservationListItem;
74 |
--------------------------------------------------------------------------------
/src/agenda/reservation-list/style.js:
--------------------------------------------------------------------------------
1 | import {StyleSheet} from 'react-native';
2 | import * as defaultStyle from '../../style';
3 |
4 | const STYLESHEET_ID = 'stylesheet.agenda.list';
5 |
6 | export default function styleConstructor(theme = {}) {
7 | const appStyle = {...defaultStyle, ...theme};
8 | return StyleSheet.create({
9 | container: {
10 | flexDirection: 'row'
11 | },
12 | dayNum: {
13 | fontSize: 28,
14 | fontWeight: '200',
15 | color: appStyle.agendaDayNumColor
16 | },
17 | dayText: {
18 | fontSize: 14,
19 | fontWeight: '300',
20 | color: appStyle.agendaDayTextColor,
21 | marginTop: -5,
22 | backgroundColor: 'rgba(0,0,0,0)'
23 | },
24 | day: {
25 | width: 63,
26 | alignItems: 'center',
27 | justifyContent: 'flex-start',
28 | marginTop: 32
29 | },
30 | today: {
31 | color: appStyle.agendaTodayColor
32 | },
33 | ...(theme[STYLESHEET_ID] || {})
34 | });
35 | }
36 |
--------------------------------------------------------------------------------
/src/agenda/style.js:
--------------------------------------------------------------------------------
1 | import {StyleSheet} from 'react-native';
2 | import * as defaultStyle from '../style';
3 | import platformStyles from './platform-style';
4 |
5 | const STYLESHEET_ID = 'stylesheet.agenda.main';
6 |
7 | export default function styleConstructor(theme = {}) {
8 | const appStyle = {...defaultStyle, ...theme};
9 | const { knob, weekdays } = platformStyles(appStyle);
10 | return StyleSheet.create({
11 | knob,
12 | weekdays,
13 | header: {
14 | overflow: 'hidden',
15 | justifyContent: 'flex-end',
16 | position:'absolute',
17 | height:'100%',
18 | width:'100%',
19 | },
20 | calendar: {
21 | flex: 1,
22 | borderBottomWidth: 1,
23 | borderColor: appStyle.separatorColor
24 | },
25 | knobContainer: {
26 | flex: 1,
27 | position: 'absolute',
28 | left: 0,
29 | right: 0,
30 | height: 24,
31 | bottom: 0,
32 | alignItems: 'center',
33 | backgroundColor: appStyle.calendarBackground
34 | },
35 | weekday: {
36 | width: 32,
37 | textAlign: 'center',
38 | fontSize: 13,
39 | color: appStyle.textSectionTitleColor,
40 | },
41 | reservations: {
42 | flex: 1,
43 | marginTop: 104,
44 | backgroundColor: appStyle.backgroundColor
45 | },
46 | ...(theme[STYLESHEET_ID] || {})
47 | });
48 | }
49 |
--------------------------------------------------------------------------------
/src/calendar-list/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {
3 | FlatList, Platform, Dimensions,
4 | } from 'react-native';
5 | import PropTypes from 'prop-types';
6 | import XDate from 'xdate';
7 |
8 | import {xdateToData, parseDate} from '../interface';
9 | import styleConstructor from './style';
10 | import dateutils from '../dateutils';
11 | import Calendar from '../calendar';
12 | import CalendarListItem from './item';
13 |
14 | const {width} = Dimensions.get('window');
15 |
16 | class CalendarList extends Component {
17 | static propTypes = {
18 | ...Calendar.propTypes,
19 |
20 | // Max amount of months allowed to scroll to the past. Default = 50
21 | pastScrollRange: PropTypes.number,
22 |
23 | // Max amount of months allowed to scroll to the future. Default = 50
24 | futureScrollRange: PropTypes.number,
25 |
26 | // Enable or disable scrolling of calendar list
27 | scrollEnabled: PropTypes.bool,
28 |
29 | // Enable or disable vertical scroll indicator. Default = false
30 | showScrollIndicator: PropTypes.bool,
31 |
32 | // When true, the calendar list scrolls to top when the status bar is tapped. Default = true
33 | scrollsToTop: PropTypes.bool,
34 |
35 | // Enable or disable paging on scroll
36 | pagingEnabled: PropTypes.bool,
37 |
38 | // Used when calendar scroll is horizontal, default is device width, pagination should be disabled
39 | calendarWidth: PropTypes.number,
40 |
41 | // Whether the scroll is horizontal
42 | horizontal: PropTypes.bool,
43 | // Dynamic calendar height
44 | calendarHeight: PropTypes.number,
45 | };
46 |
47 | static defaultProps = {
48 | horizontal: false,
49 | calendarWidth: width,
50 | calendarHeight: 360,
51 | pastScrollRange: 50,
52 | futureScrollRange: 50,
53 | showScrollIndicator: false,
54 | scrollEnabled: true,
55 | scrollsToTop: false,
56 | removeClippedSubviews: Platform.OS === 'android' ? false : true,
57 | }
58 |
59 | constructor(props) {
60 | super(props);
61 | this.style = styleConstructor(props.theme);
62 |
63 | const rows = [];
64 | const texts = [];
65 | const date = parseDate(props.current) || XDate();
66 | for (let i = 0; i <= this.props.pastScrollRange + this.props.futureScrollRange; i++) {
67 | const rangeDate = date.clone().addMonths(i - this.props.pastScrollRange, true);
68 | const rangeDateStr = rangeDate.toString('MMM yyyy');
69 | texts.push(rangeDateStr);
70 | /*
71 | * This selects range around current shown month [-0, +2] or [-1, +1] month for detail calendar rendering.
72 | * If `this.pastScrollRange` is `undefined` it's equal to `false` or 0 in next condition.
73 | */
74 | if (this.props.pastScrollRange - 1 <= i && i <= this.props.pastScrollRange + 1 || !this.props.pastScrollRange && i <= this.props.pastScrollRange + 2) {
75 | rows.push(rangeDate);
76 | } else {
77 | rows.push(rangeDateStr);
78 | }
79 | }
80 |
81 | this.state = {
82 | rows,
83 | texts,
84 | openDate: date
85 | };
86 |
87 | this.onViewableItemsChangedBound = this.onViewableItemsChanged.bind(this);
88 | this.renderCalendarBound = this.renderCalendar.bind(this);
89 | this.getItemLayout = this.getItemLayout.bind(this);
90 | this.onLayout = this.onLayout.bind(this);
91 | }
92 |
93 | onLayout(event) {
94 | if (this.props.onLayout) {
95 | this.props.onLayout(event);
96 | }
97 | }
98 |
99 | scrollToDay(d, offset, animated) {
100 | const day = parseDate(d);
101 | const diffMonths = Math.round(this.state.openDate.clone().setDate(1).diffMonths(day.clone().setDate(1)));
102 | const size = this.props.horizontal ? this.props.calendarWidth : this.props.calendarHeight;
103 | let scrollAmount = (size * this.props.pastScrollRange) + (diffMonths * size) + (offset || 0);
104 | if (!this.props.horizontal) {
105 | let week = 0;
106 | const days = dateutils.page(day, this.props.firstDay);
107 | for (let i = 0; i < days.length; i++) {
108 | week = Math.floor(i / 7);
109 | if (dateutils.sameDate(days[i], day)) {
110 | scrollAmount += 46 * week;
111 | break;
112 | }
113 | }
114 | }
115 | this.listView.scrollToOffset({offset: scrollAmount, animated});
116 | }
117 |
118 | scrollToMonth(m) {
119 | const month = parseDate(m);
120 | const scrollTo = month || this.state.openDate;
121 | let diffMonths = Math.round(this.state.openDate.clone().setDate(1).diffMonths(scrollTo.clone().setDate(1)));
122 | const size = this.props.horizontal ? this.props.calendarWidth : this.props.calendarHeight;
123 | const scrollAmount = (size * this.props.pastScrollRange) + (diffMonths * size);
124 | //console.log(month, this.state.openDate);
125 | //console.log(scrollAmount, diffMonths);
126 | this.listView.scrollToOffset({offset: scrollAmount, animated: false});
127 | }
128 |
129 | componentWillReceiveProps(props) {
130 | const current = parseDate(this.props.current);
131 | const nextCurrent = parseDate(props.current);
132 | if (nextCurrent && current && nextCurrent.getTime() !== current.getTime()) {
133 | this.scrollToMonth(nextCurrent);
134 | }
135 |
136 | const rowclone = this.state.rows;
137 | const newrows = [];
138 | for (let i = 0; i < rowclone.length; i++) {
139 | let val = this.state.texts[i];
140 | if (rowclone[i].getTime) {
141 | val = rowclone[i].clone();
142 | val.propbump = rowclone[i].propbump ? rowclone[i].propbump + 1 : 1;
143 | }
144 | newrows.push(val);
145 | }
146 | this.setState({
147 | rows: newrows
148 | });
149 | }
150 |
151 | onViewableItemsChanged({viewableItems}) {
152 | function rowIsCloseToViewable(index, distance) {
153 | for (let i = 0; i < viewableItems.length; i++) {
154 | if (Math.abs(index - parseInt(viewableItems[i].index)) <= distance) {
155 | return true;
156 | }
157 | }
158 | return false;
159 | }
160 |
161 | const rowclone = this.state.rows;
162 | const newrows = [];
163 | const visibleMonths = [];
164 | for (let i = 0; i < rowclone.length; i++) {
165 | let val = rowclone[i];
166 | const rowShouldBeRendered = rowIsCloseToViewable(i, 1);
167 | if (rowShouldBeRendered && !rowclone[i].getTime) {
168 | val = this.state.openDate.clone().addMonths(i - this.props.pastScrollRange, true);
169 | } else if (!rowShouldBeRendered) {
170 | val = this.state.texts[i];
171 | }
172 | newrows.push(val);
173 | if (rowIsCloseToViewable(i, 0)) {
174 | visibleMonths.push(xdateToData(val));
175 | }
176 | }
177 | if (this.props.onVisibleMonthsChange) {
178 | this.props.onVisibleMonthsChange(visibleMonths);
179 | }
180 | this.setState({
181 | rows: newrows
182 | });
183 | }
184 |
185 | renderCalendar({item}) {
186 | return ();
187 | }
188 |
189 | getItemLayout(data, index) {
190 | return {length: this.props.horizontal ? this.props.calendarWidth : this.props.calendarHeight, offset: (this.props.horizontal ? this.props.calendarWidth : this.props.calendarHeight) * index, index};
191 | }
192 |
193 | getMonthIndex(month) {
194 | let diffMonths = this.state.openDate.diffMonths(month) + this.props.pastScrollRange;
195 | return diffMonths;
196 | }
197 |
198 | render() {
199 | return (
200 | this.listView = c}
203 | //scrollEventThrottle={1000}
204 | style={[this.style.container, this.props.style]}
205 | initialListSize={this.pastScrollRange + this.futureScrollRange + 1}
206 | data={this.state.rows}
207 | //snapToAlignment='start'
208 | //snapToInterval={this.calendarHeight}
209 | removeClippedSubviews={this.props.removeClippedSubviews}
210 | pageSize={1}
211 | horizontal={this.props.horizontal}
212 | pagingEnabled={this.props.pagingEnabled}
213 | onViewableItemsChanged={this.onViewableItemsChangedBound}
214 | renderItem={this.renderCalendarBound}
215 | showsVerticalScrollIndicator={this.props.showScrollIndicator}
216 | showsHorizontalScrollIndicator={this.props.showScrollIndicator}
217 | scrollEnabled={this.props.scrollingEnabled}
218 | keyExtractor={(item, index) => String(index)}
219 | initialScrollIndex={this.state.openDate ? this.getMonthIndex(this.state.openDate) : false}
220 | getItemLayout={this.getItemLayout}
221 | scrollsToTop={this.props.scrollsToTop}
222 | />
223 | );
224 | }
225 | }
226 |
227 | export default CalendarList;
228 |
--------------------------------------------------------------------------------
/src/calendar-list/item.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {Text, View} from 'react-native';
3 | import Calendar from '../calendar';
4 | import styleConstructor from './style';
5 |
6 | class CalendarListItem extends Component {
7 | static defaultProps = {
8 | hideArrows: true,
9 | hideExtraDays: true,
10 | };
11 |
12 | constructor(props) {
13 | super(props);
14 | this.style = styleConstructor(props.theme);
15 | }
16 |
17 | shouldComponentUpdate(nextProps) {
18 | const r1 = this.props.item;
19 | const r2 = nextProps.item;
20 | return r1.toString('yyyy MM') !== r2.toString('yyyy MM') || !!(r2.propbump && r2.propbump !== r1.propbump);
21 | }
22 |
23 | render() {
24 | const row = this.props.item;
25 | if (row.getTime) {
26 | return (
27 | );
48 | } else {
49 | const text = row.toString();
50 | return (
51 |
52 | {text}
53 |
54 | );
55 | }
56 | }
57 | }
58 |
59 | export default CalendarListItem;
60 |
--------------------------------------------------------------------------------
/src/calendar-list/style.js:
--------------------------------------------------------------------------------
1 | import {StyleSheet} from 'react-native';
2 | import * as defaultStyle from '../style';
3 |
4 | const STYLESHEET_ID = 'stylesheet.calendar-list.main';
5 |
6 | export default function getStyle(theme={}) {
7 | const appStyle = {...defaultStyle, ...theme};
8 | return StyleSheet.create({
9 | container: {
10 | backgroundColor: appStyle.calendarBackground
11 | },
12 | placeholder: {
13 | backgroundColor: appStyle.calendarBackground,
14 | alignItems: 'center',
15 | justifyContent: 'center'
16 | },
17 | placeholderText: {
18 | fontSize: 30,
19 | fontWeight: '200',
20 | color: appStyle.dayTextColor
21 | },
22 | calendar: {
23 | paddingLeft: 15,
24 | paddingRight: 15
25 | },
26 | ...(theme[STYLESHEET_ID] || {})
27 | });
28 | }
29 |
--------------------------------------------------------------------------------
/src/calendar/day/basic/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {
3 | TouchableOpacity,
4 | Text,
5 | View
6 | } from 'react-native';
7 | import PropTypes from 'prop-types';
8 | import {shouldUpdate} from '../../../component-updater';
9 |
10 | import styleConstructor from './style';
11 |
12 | class Day extends Component {
13 | static propTypes = {
14 | // TODO: disabled props should be removed
15 | state: PropTypes.oneOf(['disabled', 'today', '']),
16 |
17 | // Specify theme properties to override specific styles for calendar parts. Default = {}
18 | theme: PropTypes.object,
19 | marking: PropTypes.any,
20 | onPress: PropTypes.func,
21 | onLongPress: PropTypes.func,
22 | date: PropTypes.object
23 | };
24 |
25 | constructor(props) {
26 | super(props);
27 | this.style = styleConstructor(props.theme);
28 | this.onDayPress = this.onDayPress.bind(this);
29 | this.onDayLongPress = this.onDayLongPress.bind(this);
30 | }
31 |
32 | onDayPress() {
33 | this.props.onPress(this.props.date);
34 | }
35 | onDayLongPress() {
36 | this.props.onLongPress(this.props.date);
37 | }
38 |
39 | shouldComponentUpdate(nextProps) {
40 | return shouldUpdate(this.props, nextProps, ['state', 'children', 'marking', 'onPress', 'onLongPress']);
41 | }
42 |
43 | render() {
44 | const containerStyle = [this.style.base];
45 | const textStyle = [this.style.text];
46 | const dotStyle = [this.style.dot];
47 |
48 | let marking = this.props.marking || {};
49 | if (marking && marking.constructor === Array && marking.length) {
50 | marking = {
51 | marking: true
52 | };
53 | }
54 | const isDisabled = typeof marking.disabled !== 'undefined' ? marking.disabled : this.props.state === 'disabled';
55 | let dot;
56 | if (marking.marked) {
57 | dotStyle.push(this.style.visibleDot);
58 | if (marking.dotColor) {
59 | dotStyle.push({backgroundColor: marking.dotColor});
60 | }
61 | dot = ();
62 | }
63 |
64 | if (marking.selected) {
65 | containerStyle.push(this.style.selected);
66 | if (marking.selectedColor) {
67 | containerStyle.push({backgroundColor: marking.selectedColor});
68 | }
69 | dotStyle.push(this.style.selectedDot);
70 | textStyle.push(this.style.selectedText);
71 | } else if (isDisabled) {
72 | textStyle.push(this.style.disabledText);
73 | } else if (this.props.state === 'today') {
74 | containerStyle.push(this.style.today);
75 | textStyle.push(this.style.todayText);
76 | }
77 |
78 | return (
79 |
86 | {String(this.props.children)}
87 | {dot}
88 |
89 | );
90 | }
91 | }
92 |
93 | export default Day;
94 |
--------------------------------------------------------------------------------
/src/calendar/day/basic/style.js:
--------------------------------------------------------------------------------
1 | import {StyleSheet, Platform} from 'react-native';
2 | import * as defaultStyle from '../../../style';
3 |
4 | const STYLESHEET_ID = 'stylesheet.day.basic';
5 |
6 | export default function styleConstructor(theme={}) {
7 | const appStyle = {...defaultStyle, ...theme};
8 | return StyleSheet.create({
9 | base: {
10 | width: 32,
11 | height: 32,
12 | alignItems: 'center'
13 | },
14 | text: {
15 | marginTop: Platform.OS === 'android' ? 4 : 6,
16 | fontSize: appStyle.textDayFontSize,
17 | fontFamily: appStyle.textDayFontFamily,
18 | fontWeight: '300',
19 | color: appStyle.dayTextColor,
20 | backgroundColor: 'rgba(255, 255, 255, 0)'
21 | },
22 | alignedText: {
23 | marginTop: Platform.OS === 'android' ? 4 : 6
24 | },
25 | selected: {
26 | backgroundColor: appStyle.selectedDayBackgroundColor,
27 | borderRadius: 16
28 | },
29 | today: {
30 | backgroundColor: appStyle.todayBackgroundColor
31 | },
32 | todayText: {
33 | color: appStyle.todayTextColor
34 | },
35 | selectedText: {
36 | color: appStyle.selectedDayTextColor
37 | },
38 | disabledText: {
39 | color: appStyle.textDisabledColor
40 | },
41 | dot: {
42 | width: 4,
43 | height: 4,
44 | marginTop: 1,
45 | borderRadius: 2,
46 | opacity: 0
47 | },
48 | visibleDot: {
49 | opacity: 1,
50 | backgroundColor: appStyle.dotColor
51 | },
52 | selectedDot: {
53 | backgroundColor: appStyle.selectedDotColor
54 | },
55 | ...(theme[STYLESHEET_ID] || {})
56 | });
57 | }
58 |
--------------------------------------------------------------------------------
/src/calendar/day/custom/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {
3 | TouchableOpacity,
4 | Text,
5 | } from 'react-native';
6 | import PropTypes from 'prop-types';
7 |
8 | import styleConstructor from './style';
9 | import {shouldUpdate} from '../../../component-updater';
10 |
11 | class Day extends Component {
12 | static propTypes = {
13 | // TODO: disabled props should be removed
14 | state: PropTypes.oneOf(['selected', 'disabled', 'today', '']),
15 |
16 | // Specify theme properties to override specific styles for calendar parts. Default = {}
17 | theme: PropTypes.object,
18 | marking: PropTypes.any,
19 | onPress: PropTypes.func,
20 | date: PropTypes.object
21 | };
22 |
23 | constructor(props) {
24 | super(props);
25 | this.style = styleConstructor(props.theme);
26 | this.onDayPress = this.onDayPress.bind(this);
27 | this.onDayLongPress = this.onDayLongPress.bind(this);
28 | }
29 |
30 | onDayPress() {
31 | this.props.onPress(this.props.date);
32 | }
33 | onDayLongPress() {
34 | this.props.onLongPress(this.props.date);
35 | }
36 |
37 | shouldComponentUpdate(nextProps) {
38 | return shouldUpdate(this.props, nextProps, ['state', 'children', 'marking', 'onPress', 'onLongPress']);
39 | }
40 |
41 | render() {
42 | let containerStyle = [this.style.base];
43 | let textStyle = [this.style.text];
44 |
45 | let marking = this.props.marking || {};
46 | if (marking && marking.constructor === Array && marking.length) {
47 | marking = {
48 | marking: true
49 | };
50 | }
51 | const isDisabled = typeof marking.disabled !== 'undefined' ? marking.disabled : this.props.state === 'disabled';
52 |
53 | if (marking.selected) {
54 | containerStyle.push(this.style.selected);
55 | } else if (isDisabled) {
56 | textStyle.push(this.style.disabledText);
57 | } else if (this.props.state === 'today') {
58 | containerStyle.push(this.style.today);
59 | textStyle.push(this.style.todayText);
60 | }
61 |
62 | if (marking.customStyles && typeof marking.customStyles === 'object') {
63 | const styles = marking.customStyles;
64 | if (styles.container) {
65 | if (styles.container.borderRadius === undefined) {
66 | styles.container.borderRadius = 16;
67 | }
68 | containerStyle.push(styles.container);
69 | }
70 | if (styles.text) {
71 | textStyle.push(styles.text);
72 | }
73 | }
74 |
75 | return (
76 |
83 | {String(this.props.children)}
84 |
85 | );
86 | }
87 | }
88 |
89 | export default Day;
90 |
--------------------------------------------------------------------------------
/src/calendar/day/custom/style.js:
--------------------------------------------------------------------------------
1 | import {StyleSheet, Platform} from 'react-native';
2 | import * as defaultStyle from '../../../style';
3 |
4 | const STYLESHEET_ID = 'stylesheet.day.single';
5 |
6 | export default function styleConstructor(theme={}) {
7 | const appStyle = {...defaultStyle, ...theme};
8 | return StyleSheet.create({
9 | base: {
10 | width: 32,
11 | height: 32,
12 | alignItems: 'center'
13 | },
14 | text: {
15 | marginTop: Platform.OS === 'android' ? 4 : 6,
16 | fontSize: appStyle.textDayFontSize,
17 | fontFamily: appStyle.textDayFontFamily,
18 | fontWeight: '300',
19 | color: appStyle.dayTextColor,
20 | backgroundColor: 'rgba(255, 255, 255, 0)'
21 | },
22 | alignedText: {
23 | marginTop: Platform.OS === 'android' ? 4 : 6
24 | },
25 | selected: {
26 | backgroundColor: appStyle.selectedDayBackgroundColor,
27 | borderRadius: 16
28 | },
29 | today: {
30 | backgroundColor: appStyle.todayBackgroundColor
31 | },
32 | todayText: {
33 | color: appStyle.todayTextColor
34 | },
35 | selectedText: {
36 | color: appStyle.selectedDayTextColor
37 | },
38 | disabledText: {
39 | color: appStyle.textDisabledColor
40 | },
41 | ...(theme[STYLESHEET_ID] || {})
42 | });
43 | }
44 |
--------------------------------------------------------------------------------
/src/calendar/day/multi-dot/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {
3 | TouchableOpacity,
4 | Text,
5 | View
6 | } from 'react-native';
7 | import PropTypes from 'prop-types';
8 |
9 | import {shouldUpdate} from '../../../component-updater';
10 |
11 | import styleConstructor from './style';
12 |
13 | class Day extends Component {
14 | static propTypes = {
15 | // TODO: disabled props should be removed
16 | state: PropTypes.oneOf(['disabled', 'today', '']),
17 |
18 | // Specify theme properties to override specific styles for calendar parts. Default = {}
19 | theme: PropTypes.object,
20 | marking: PropTypes.any,
21 | onPress: PropTypes.func,
22 | onLongPress: PropTypes.func,
23 | date: PropTypes.object
24 | };
25 |
26 | constructor(props) {
27 | super(props);
28 | this.style = styleConstructor(props.theme);
29 | this.onDayPress = this.onDayPress.bind(this);
30 | this.onDayLongPress = this.onDayLongPress.bind(this);
31 | }
32 |
33 | onDayPress() {
34 | this.props.onPress(this.props.date);
35 | }
36 |
37 | onDayLongPress() {
38 | this.props.onLongPress(this.props.date);
39 | }
40 |
41 | shouldComponentUpdate(nextProps) {
42 | return shouldUpdate(this.props, nextProps, ['state', 'children', 'marking', 'onPress', 'onLongPress']);
43 | }
44 |
45 | renderDots(marking) {
46 | const baseDotStyle = [this.style.dot, this.style.visibleDot];
47 | if (marking.dots && Array.isArray(marking.dots) && marking.dots.length > 0) {
48 | // Filter out dots so that we we process only those items which have key and color property
49 | const validDots = marking.dots.filter(d => (d && d.color));
50 | return validDots.map((dot, index) => {
51 | return (
52 |
54 | );
55 | });
56 | }
57 | return;
58 | }
59 |
60 | render() {
61 | const containerStyle = [this.style.base];
62 | const textStyle = [this.style.text];
63 |
64 | const marking = this.props.marking || {};
65 | const dot = this.renderDots(marking);
66 |
67 | if (marking.selected) {
68 | containerStyle.push(this.style.selected);
69 | textStyle.push(this.style.selectedText);
70 | if (marking.selectedColor) {
71 | containerStyle.push({backgroundColor: marking.selectedColor});
72 | }
73 | } else if (typeof marking.disabled !== 'undefined' ? marking.disabled : this.props.state === 'disabled') {
74 | textStyle.push(this.style.disabledText);
75 | } else if (this.props.state === 'today') {
76 | containerStyle.push(this.style.today);
77 | textStyle.push(this.style.todayText);
78 | }
79 | return (
80 |
84 | {String(this.props.children)}
85 | {dot}
86 |
87 | );
88 | }
89 | }
90 |
91 | export default Day;
92 |
--------------------------------------------------------------------------------
/src/calendar/day/multi-dot/style.js:
--------------------------------------------------------------------------------
1 | import {StyleSheet, Platform} from 'react-native';
2 | import * as defaultStyle from '../../../style';
3 |
4 | const STYLESHEET_ID = 'stylesheet.day.multiDot';
5 |
6 | export default function styleConstructor(theme={}) {
7 | const appStyle = {...defaultStyle, ...theme};
8 | return StyleSheet.create({
9 | base: {
10 | width: 32,
11 | height: 32,
12 | alignItems: 'center'
13 | },
14 | text: {
15 | marginTop: 4,
16 | fontSize: appStyle.textDayFontSize,
17 | fontFamily: appStyle.textDayFontFamily,
18 | fontWeight: '300',
19 | color: appStyle.dayTextColor,
20 | backgroundColor: 'rgba(255, 255, 255, 0)'
21 | },
22 | alignedText: {
23 | marginTop: Platform.OS === 'android' ? 4 : 6
24 | },
25 | selected: {
26 | backgroundColor: appStyle.selectedDayBackgroundColor,
27 | borderRadius: 16
28 | },
29 | today: {
30 | backgroundColor: appStyle.todayBackgroundColor
31 | },
32 | todayText: {
33 | color: appStyle.todayTextColor
34 | },
35 | selectedText: {
36 | color: appStyle.selectedDayTextColor
37 | },
38 | disabledText: {
39 | color: appStyle.textDisabledColor
40 | },
41 | dot: {
42 | width: 4,
43 | height: 4,
44 | marginTop: 1,
45 | marginLeft: 1,
46 | marginRight: 1,
47 | borderRadius: 2,
48 | opacity: 0
49 | },
50 | visibleDot: {
51 | opacity: 1,
52 | backgroundColor: appStyle.dotColor
53 | },
54 | selectedDot: {
55 | backgroundColor: appStyle.selectedDotColor
56 | },
57 | ...(theme[STYLESHEET_ID] || {})
58 | });
59 | }
60 |
--------------------------------------------------------------------------------
/src/calendar/day/multi-period/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { TouchableOpacity, Text, View } from 'react-native';
3 | import PropTypes from 'prop-types';
4 | import {shouldUpdate} from '../../../component-updater';
5 |
6 | import styleConstructor from './style';
7 |
8 | class Day extends Component {
9 | static propTypes = {
10 | // TODO: disabled props should be removed
11 | state: PropTypes.oneOf(['disabled', 'today', '']),
12 |
13 | // Specify theme properties to override specific styles for calendar parts. Default = {}
14 | theme: PropTypes.object,
15 | marking: PropTypes.any,
16 | onPress: PropTypes.func,
17 | date: PropTypes.object,
18 | };
19 |
20 | constructor(props) {
21 | super(props);
22 | this.style = styleConstructor(props.theme);
23 | this.onDayPress = this.onDayPress.bind(this);
24 | }
25 |
26 | onDayPress() {
27 | this.props.onPress(this.props.date);
28 | }
29 |
30 | shouldComponentUpdate(nextProps) {
31 | return shouldUpdate(this.props, nextProps, ['state', 'children', 'marking', 'onPress', 'onLongPress']);
32 | }
33 |
34 | renderPeriods(marking) {
35 | const baseDotStyle = [this.style.dot, this.style.visibleDot];
36 | if (
37 | marking.periods &&
38 | Array.isArray(marking.periods) &&
39 | marking.periods.length > 0
40 | ) {
41 | // Filter out dots so that we we process only those items which have key and color property
42 | const validPeriods = marking.periods.filter(d => d && d.color);
43 | return validPeriods.map((period, index) => {
44 | const style = [
45 | ...baseDotStyle,
46 | {
47 | backgroundColor: period.color,
48 | },
49 | ];
50 | if (period.startingDay) {
51 | style.push({
52 | borderTopLeftRadius: 2,
53 | borderBottomLeftRadius: 2,
54 | marginLeft: 4,
55 | });
56 | }
57 | if (period.endingDay) {
58 | style.push({
59 | borderTopRightRadius: 2,
60 | borderBottomRightRadius: 2,
61 | marginRight: 4,
62 | });
63 | }
64 | return ;
65 | });
66 | }
67 | return;
68 | }
69 |
70 | render() {
71 | const containerStyle = [this.style.base];
72 | const textStyle = [this.style.text];
73 |
74 | const marking = this.props.marking || {};
75 | const periods = this.renderPeriods(marking);
76 |
77 | if (marking.selected) {
78 | containerStyle.push(this.style.selected);
79 | textStyle.push(this.style.selectedText);
80 | } else if (
81 | typeof marking.disabled !== 'undefined'
82 | ? marking.disabled
83 | : this.props.state === 'disabled'
84 | ) {
85 | textStyle.push(this.style.disabledText);
86 | } else if (this.props.state === 'today') {
87 | containerStyle.push(this.style.today);
88 | textStyle.push(this.style.todayText);
89 | }
90 | return (
91 |
97 |
98 |
99 | {String(this.props.children)}
100 |
101 |
102 |
106 | {periods}
107 |
108 |
109 | );
110 | }
111 | }
112 |
113 | export default Day;
114 |
--------------------------------------------------------------------------------
/src/calendar/day/multi-period/style.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Platform } from 'react-native';
2 | import * as defaultStyle from '../../../style';
3 |
4 | const STYLESHEET_ID = 'stylesheet.day.basic';
5 |
6 | export default function styleConstructor(theme = {}) {
7 | const appStyle = { ...defaultStyle, ...theme };
8 | return StyleSheet.create({
9 | base: {
10 | width: 32,
11 | height: 32,
12 | alignItems: 'center',
13 | },
14 | text: {
15 | marginTop: Platform.OS === 'android' ? 4 : 6,
16 | fontSize: appStyle.textDayFontSize,
17 | fontFamily: appStyle.textDayFontFamily,
18 | fontWeight: '300',
19 | color: appStyle.dayTextColor,
20 | backgroundColor: 'rgba(255, 255, 255, 0)',
21 | },
22 | alignedText: {
23 | marginTop: Platform.OS === 'android' ? 4 : 6,
24 | },
25 | selected: {
26 | backgroundColor: appStyle.selectedDayBackgroundColor,
27 | borderRadius: 16,
28 | },
29 | today: {
30 | backgroundColor: appStyle.todayBackgroundColor
31 | },
32 | todayText: {
33 | color: appStyle.todayTextColor,
34 | },
35 | selectedText: {
36 | color: appStyle.selectedDayTextColor,
37 | },
38 | disabledText: {
39 | color: appStyle.textDisabledColor,
40 | },
41 | dot: {
42 | // width: 42,
43 | height: 4,
44 | marginVertical: 1,
45 | // borderRadius: 2,
46 | opacity: 0,
47 | },
48 | leftFiller: {
49 | width: 4,
50 | height: 4,
51 | marginTop: 1,
52 | marginRight: -2,
53 | },
54 | rightFiller: {
55 | width: 4,
56 | height: 4,
57 | marginTop: 1,
58 | marginLeft: -2,
59 | },
60 | rounded: {
61 | borderRadius: 2,
62 | },
63 | visibleDot: {
64 | opacity: 1,
65 | backgroundColor: appStyle.dotColor,
66 | },
67 | selectedDot: {
68 | backgroundColor: appStyle.selectedDotColor,
69 | },
70 | startingPeriod: {
71 | width: 18,
72 | height: 4,
73 | marginTop: 1,
74 | borderRadius: 2,
75 | opacity: 0,
76 | },
77 | ...(theme[STYLESHEET_ID] || {}),
78 | });
79 | }
80 |
--------------------------------------------------------------------------------
/src/calendar/day/period/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | TouchableWithoutFeedback,
5 | Text,
6 | View
7 | } from 'react-native';
8 | import {shouldUpdate} from '../../../component-updater';
9 | import isEqual from 'lodash.isequal';
10 |
11 | import * as defaultStyle from '../../../style';
12 | import styleConstructor from './style';
13 |
14 | class Day extends Component {
15 | static propTypes = {
16 | // TODO: selected + disabled props should be removed
17 | state: PropTypes.oneOf(['selected', 'disabled', 'today', '']),
18 |
19 | // Specify theme properties to override specific styles for calendar parts. Default = {}
20 | theme: PropTypes.object,
21 | marking: PropTypes.any,
22 |
23 | onPress: PropTypes.func,
24 | onLongPress: PropTypes.func,
25 | date: PropTypes.object,
26 |
27 | markingExists: PropTypes.bool,
28 | };
29 |
30 | constructor(props) {
31 | super(props);
32 | this.theme = {...defaultStyle, ...(props.theme || {})};
33 | this.style = styleConstructor(props.theme);
34 | this.markingStyle = this.getDrawingStyle(props.marking || []);
35 | this.onDayPress = this.onDayPress.bind(this);
36 | this.onDayLongPress = this.onDayLongPress.bind(this);
37 | }
38 |
39 | onDayPress() {
40 | this.props.onPress(this.props.date);
41 | }
42 |
43 | onDayLongPress() {
44 | this.props.onLongPress(this.props.date);
45 | }
46 |
47 | shouldComponentUpdate(nextProps) {
48 | const newMarkingStyle = this.getDrawingStyle(nextProps.marking);
49 |
50 | if (!isEqual(this.markingStyle, newMarkingStyle)) {
51 | this.markingStyle = newMarkingStyle;
52 | return true;
53 | }
54 |
55 | return shouldUpdate(this.props, nextProps, ['state', 'children', 'onPress', 'onLongPress']);
56 | }
57 |
58 | getDrawingStyle(marking) {
59 | const defaultStyle = {textStyle: {}};
60 | if (!marking) {
61 | return defaultStyle;
62 | }
63 | if (marking.disabled) {
64 | defaultStyle.textStyle.color = this.theme.textDisabledColor;
65 | } else if (marking.selected) {
66 | defaultStyle.textStyle.color = this.theme.selectedDayTextColor;
67 | }
68 | const resultStyle = ([marking]).reduce((prev, next) => {
69 | if (next.quickAction) {
70 | if (next.first || next.last) {
71 | prev.containerStyle = this.style.firstQuickAction;
72 | prev.textStyle = this.style.firstQuickActionText;
73 | if (next.endSelected && next.first && !next.last) {
74 | prev.rightFillerStyle = '#c1e4fe';
75 | } else if (next.endSelected && next.last && !next.first) {
76 | prev.leftFillerStyle = '#c1e4fe';
77 | }
78 | } else if (!next.endSelected) {
79 | prev.containerStyle = this.style.quickAction;
80 | prev.textStyle = this.style.quickActionText;
81 | } else if (next.endSelected) {
82 | prev.leftFillerStyle = '#c1e4fe';
83 | prev.rightFillerStyle = '#c1e4fe';
84 | }
85 | return prev;
86 | }
87 |
88 | const color = next.color;
89 | if (next.status === 'NotAvailable') {
90 | prev.textStyle = this.style.naText;
91 | }
92 | if (next.startingDay) {
93 | prev.startingDay = {
94 | color
95 | };
96 | }
97 | if (next.endingDay) {
98 | prev.endingDay = {
99 | color
100 | };
101 | }
102 | if (!next.startingDay && !next.endingDay) {
103 | prev.day = {
104 | color
105 | };
106 | }
107 | if (next.textColor) {
108 | prev.textStyle.color = next.textColor;
109 | }
110 | return prev;
111 | }, defaultStyle);
112 | return resultStyle;
113 | }
114 |
115 | render() {
116 | const containerStyle = [this.style.base];
117 | const textStyle = [this.style.text];
118 | let leftFillerStyle = {};
119 | let rightFillerStyle = {};
120 | let fillerStyle = {};
121 | let fillers;
122 |
123 | if (this.props.state === 'disabled') {
124 | textStyle.push(this.style.disabledText);
125 | } else if (this.props.state === 'today') {
126 | containerStyle.push(this.style.today);
127 | textStyle.push(this.style.todayText);
128 | }
129 |
130 | if (this.props.marking) {
131 | containerStyle.push({
132 | borderRadius: 17
133 | });
134 |
135 | const flags = this.markingStyle;
136 | if (flags.textStyle) {
137 | textStyle.push(flags.textStyle);
138 | }
139 | if (flags.containerStyle) {
140 | containerStyle.push(flags.containerStyle);
141 | }
142 | if (flags.leftFillerStyle) {
143 | leftFillerStyle.backgroundColor = flags.leftFillerStyle;
144 | }
145 | if (flags.rightFillerStyle) {
146 | rightFillerStyle.backgroundColor = flags.rightFillerStyle;
147 | }
148 |
149 | if (flags.startingDay && !flags.endingDay) {
150 | leftFillerStyle = {
151 | backgroundColor: this.theme.calendarBackground
152 | };
153 | rightFillerStyle = {
154 | backgroundColor: flags.startingDay.color
155 | };
156 | containerStyle.push({
157 | backgroundColor: flags.startingDay.color
158 | });
159 | } else if (flags.endingDay && !flags.startingDay) {
160 | rightFillerStyle = {
161 | backgroundColor: this.theme.calendarBackground
162 | };
163 | leftFillerStyle = {
164 | backgroundColor: flags.endingDay.color
165 | };
166 | containerStyle.push({
167 | backgroundColor: flags.endingDay.color
168 | });
169 | } else if (flags.day) {
170 | leftFillerStyle = {backgroundColor: flags.day.color};
171 | rightFillerStyle = {backgroundColor: flags.day.color};
172 | // #177 bug
173 | fillerStyle = {backgroundColor: flags.day.color};
174 | } else if (flags.endingDay && flags.startingDay) {
175 | rightFillerStyle = {
176 | backgroundColor: this.theme.calendarBackground
177 | };
178 | leftFillerStyle = {
179 | backgroundColor: this.theme.calendarBackground
180 | };
181 | containerStyle.push({
182 | backgroundColor: flags.endingDay.color
183 | });
184 | }
185 |
186 | fillers = (
187 |
188 |
189 |
190 |
191 | );
192 | }
193 |
194 | return (
195 |
198 |
199 | {fillers}
200 |
201 | {String(this.props.children)}
202 |
203 |
204 |
205 | );
206 | }
207 | }
208 |
209 | export default Day;
210 |
--------------------------------------------------------------------------------
/src/calendar/day/period/style.js:
--------------------------------------------------------------------------------
1 | import {StyleSheet} from 'react-native';
2 | import * as defaultStyle from '../../../style';
3 |
4 | const STYLESHEET_ID = 'stylesheet.day.period';
5 |
6 | const FILLER_HEIGHT = 34;
7 |
8 | export default function styleConstructor(theme={}) {
9 | const appStyle = {...defaultStyle, ...theme};
10 | return StyleSheet.create({
11 | wrapper: {
12 | flex: 1,
13 | alignItems: 'center',
14 | alignSelf: 'stretch',
15 | marginLeft: -1
16 | },
17 | base: {
18 | //borderWidth: 1,
19 | width: 38,
20 | height: FILLER_HEIGHT,
21 | alignItems: 'center'
22 | },
23 | fillers: {
24 | position: 'absolute',
25 | height: FILLER_HEIGHT,
26 | flexDirection: 'row',
27 | left: 0,
28 | right: 0
29 | },
30 | leftFiller: {
31 | height: FILLER_HEIGHT,
32 | flex: 1
33 | },
34 | rightFiller: {
35 | height: FILLER_HEIGHT,
36 | flex: 1
37 | },
38 | text: {
39 | marginTop: 7,
40 | fontSize: appStyle.textDayFontSize,
41 | fontFamily: appStyle.textDayFontFamily,
42 | fontWeight: '300',
43 | color: appStyle.dayTextColor || '#2d4150',
44 | backgroundColor: 'rgba(255, 255, 255, 0)'
45 | },
46 | today: {
47 | backgroundColor: appStyle.todayBackgroundColor
48 | },
49 | todayText: {
50 | fontWeight: '500',
51 | color: theme.todayTextColor || appStyle.dayTextColor,
52 | //color: appStyle.textLinkColor
53 | },
54 | disabledText: {
55 | color: appStyle.textDisabledColor
56 | },
57 | quickAction: {
58 | backgroundColor: 'white',
59 | borderWidth: 1,
60 | borderColor: '#c1e4fe'
61 | },
62 | quickActionText: {
63 | marginTop: 6,
64 | color: appStyle.textColor
65 | },
66 | firstQuickAction: {
67 | backgroundColor: appStyle.textLinkColor
68 | },
69 | firstQuickActionText: {
70 | color: 'white'
71 | },
72 | naText: {
73 | color: '#b6c1cd'
74 | },
75 | ...(theme[STYLESHEET_ID] || {})
76 | });
77 | }
78 |
--------------------------------------------------------------------------------
/src/calendar/header/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { ActivityIndicator } from 'react-native';
3 | import { View, Text, TouchableOpacity, Image } from 'react-native';
4 | import XDate from 'xdate';
5 | import PropTypes from 'prop-types';
6 | import styleConstructor from './style';
7 | import { weekDayNames } from '../../dateutils';
8 | import {
9 | CHANGE_MONTH_LEFT_ARROW,
10 | CHANGE_MONTH_RIGHT_ARROW
11 | } from '../../testIDs';
12 |
13 | class CalendarHeader extends Component {
14 | static propTypes = {
15 | theme: PropTypes.object,
16 | hideArrows: PropTypes.bool,
17 | month: PropTypes.instanceOf(XDate),
18 | addMonth: PropTypes.func,
19 | showIndicator: PropTypes.bool,
20 | firstDay: PropTypes.number,
21 | renderArrow: PropTypes.func,
22 | hideDayNames: PropTypes.bool,
23 | weekNumbers: PropTypes.bool,
24 | onPressArrowLeft: PropTypes.func,
25 | onPressArrowRight: PropTypes.func
26 | };
27 |
28 | static defaultProps = {
29 | monthFormat: 'MMMM yyyy',
30 | };
31 |
32 | constructor(props) {
33 | super(props);
34 | this.style = styleConstructor(props.theme);
35 | this.addMonth = this.addMonth.bind(this);
36 | this.substractMonth = this.substractMonth.bind(this);
37 | this.onPressLeft = this.onPressLeft.bind(this);
38 | this.onPressRight = this.onPressRight.bind(this);
39 | }
40 |
41 | addMonth() {
42 | this.props.addMonth(1);
43 | }
44 |
45 | substractMonth() {
46 | this.props.addMonth(-1);
47 | }
48 |
49 | shouldComponentUpdate(nextProps) {
50 | if (
51 | nextProps.month.toString('yyyy MM') !==
52 | this.props.month.toString('yyyy MM')
53 | ) {
54 | return true;
55 | }
56 | if (nextProps.showIndicator !== this.props.showIndicator) {
57 | return true;
58 | }
59 | if (nextProps.hideDayNames !== this.props.hideDayNames) {
60 | return true;
61 | }
62 | return false;
63 | }
64 |
65 | onPressLeft() {
66 | const {onPressArrowLeft} = this.props;
67 | if(typeof onPressArrowLeft === 'function') {
68 | return onPressArrowLeft(this.substractMonth);
69 | }
70 | return this.substractMonth();
71 | }
72 |
73 | onPressRight() {
74 | const {onPressArrowRight} = this.props;
75 | if(typeof onPressArrowRight === 'function') {
76 | return onPressArrowRight(this.addMonth);
77 | }
78 | return this.addMonth();
79 | }
80 |
81 | render() {
82 | let leftArrow = ;
83 | let rightArrow = ;
84 | let weekDaysNames = weekDayNames(this.props.firstDay);
85 | if (!this.props.hideArrows) {
86 | leftArrow = (
87 |
93 | {this.props.renderArrow
94 | ? this.props.renderArrow('left')
95 | : }
99 |
100 | );
101 | rightArrow = (
102 |
108 | {this.props.renderArrow
109 | ? this.props.renderArrow('right')
110 | : }
114 |
115 | );
116 | }
117 | let indicator;
118 | if (this.props.showIndicator) {
119 | indicator = ;
120 | }
121 | return (
122 |
123 |
124 | {leftArrow}
125 |
126 |
127 | {this.props.month.toString(this.props.monthFormat)}
128 |
129 | {indicator}
130 |
131 | {rightArrow}
132 |
133 | {
134 | !this.props.hideDayNames &&
135 |
136 | {this.props.weekNumbers && }
137 | {weekDaysNames.map((day, idx) => (
138 | {day}
139 | ))}
140 |
141 | }
142 |
143 | );
144 | }
145 | }
146 |
147 | export default CalendarHeader;
148 |
--------------------------------------------------------------------------------
/src/calendar/header/style.js:
--------------------------------------------------------------------------------
1 | import {StyleSheet, Platform} from 'react-native';
2 | import * as defaultStyle from '../../style';
3 |
4 | const STYLESHEET_ID = 'stylesheet.calendar.header';
5 |
6 | export default function(theme={}) {
7 | const appStyle = {...defaultStyle, ...theme};
8 | return StyleSheet.create({
9 | header: {
10 | flexDirection: 'row',
11 | justifyContent: 'space-between',
12 | paddingLeft: 10,
13 | paddingRight: 10,
14 | alignItems: 'center'
15 | },
16 | monthText: {
17 | fontSize: appStyle.textMonthFontSize,
18 | fontFamily: appStyle.textMonthFontFamily,
19 | fontWeight: appStyle.textMonthFontWeight,
20 | color: appStyle.monthTextColor,
21 | margin: 10
22 | },
23 | arrow: {
24 | padding: 10
25 | },
26 | arrowImage: {
27 | ...Platform.select({
28 | ios: {
29 | tintColor: appStyle.arrowColor
30 | },
31 | android: {
32 | tintColor: appStyle.arrowColor
33 | }
34 | })
35 | },
36 | week: {
37 | marginTop: 7,
38 | flexDirection: 'row',
39 | justifyContent: 'space-around'
40 | },
41 | dayHeader: {
42 | marginTop: 2,
43 | marginBottom: 7,
44 | width: 32,
45 | textAlign: 'center',
46 | fontSize: appStyle.textDayHeaderFontSize,
47 | fontFamily: appStyle.textDayHeaderFontFamily,
48 | color: appStyle.textSectionTitleColor
49 | },
50 | ...(theme[STYLESHEET_ID] || {})
51 | });
52 | }
53 |
--------------------------------------------------------------------------------
/src/calendar/img/next.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/src/calendar/img/next.png
--------------------------------------------------------------------------------
/src/calendar/img/next@1.5x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/src/calendar/img/next@1.5x.android.png
--------------------------------------------------------------------------------
/src/calendar/img/next@2x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/src/calendar/img/next@2x.android.png
--------------------------------------------------------------------------------
/src/calendar/img/next@2x.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/src/calendar/img/next@2x.ios.png
--------------------------------------------------------------------------------
/src/calendar/img/next@3x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/src/calendar/img/next@3x.android.png
--------------------------------------------------------------------------------
/src/calendar/img/next@4x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/src/calendar/img/next@4x.android.png
--------------------------------------------------------------------------------
/src/calendar/img/previous.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/src/calendar/img/previous.png
--------------------------------------------------------------------------------
/src/calendar/img/previous@1.5x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/src/calendar/img/previous@1.5x.android.png
--------------------------------------------------------------------------------
/src/calendar/img/previous@2x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/src/calendar/img/previous@2x.android.png
--------------------------------------------------------------------------------
/src/calendar/img/previous@2x.ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/src/calendar/img/previous@2x.ios.png
--------------------------------------------------------------------------------
/src/calendar/img/previous@3x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/src/calendar/img/previous@3x.android.png
--------------------------------------------------------------------------------
/src/calendar/img/previous@4x.android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/entria/react-native-calendars/73f8a7b497aba06d56397ec86f295fd1ea6adf9c/src/calendar/img/previous@4x.android.png
--------------------------------------------------------------------------------
/src/calendar/index.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {
3 | View,
4 | ViewPropTypes
5 | } from 'react-native';
6 | import PropTypes from 'prop-types';
7 |
8 | import XDate from 'xdate';
9 | import dateutils from '../dateutils';
10 | import {xdateToData, parseDate} from '../interface';
11 | import styleConstructor from './style';
12 | import Day from './day/basic';
13 | import UnitDay from './day/period';
14 | import MultiDotDay from './day/multi-dot';
15 | import MultiPeriodDay from './day/multi-period';
16 | import SingleDay from './day/custom';
17 | import CalendarHeader from './header';
18 | import shouldComponentUpdate from './updater';
19 |
20 | //Fallback when RN version is < 0.44
21 | const viewPropTypes = ViewPropTypes || View.propTypes;
22 |
23 | const EmptyArray = [];
24 |
25 | class Calendar extends Component {
26 | static propTypes = {
27 | // Specify theme properties to override specific styles for calendar parts. Default = {}
28 | theme: PropTypes.object,
29 | // Collection of dates that have to be marked. Default = {}
30 | markedDates: PropTypes.object,
31 |
32 | // Specify style for calendar container element. Default = {}
33 | style: viewPropTypes.style,
34 | // Initially visible month. Default = Date()
35 | current: PropTypes.any,
36 | // Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
37 | minDate: PropTypes.any,
38 | // Maximum date that can be selected, dates after maxDate will be grayed out. Default = undefined
39 | maxDate: PropTypes.any,
40 |
41 | // If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
42 | firstDay: PropTypes.number,
43 |
44 | // Date marking style [simple/period/multi-dot/multi-period]. Default = 'simple'
45 | markingType: PropTypes.string,
46 |
47 | // Hide month navigation arrows. Default = false
48 | hideArrows: PropTypes.bool,
49 | // Display loading indicador. Default = false
50 | displayLoadingIndicator: PropTypes.bool,
51 | // Do not show days of other months in month page. Default = false
52 | hideExtraDays: PropTypes.bool,
53 |
54 | // Handler which gets executed on day press. Default = undefined
55 | onDayPress: PropTypes.func,
56 | // Handler which gets executed on day long press. Default = undefined
57 | onDayLongPress: PropTypes.func,
58 | // Handler which gets executed when visible month changes in calendar. Default = undefined
59 | onMonthChange: PropTypes.func,
60 | onVisibleMonthsChange: PropTypes.func,
61 | // Replace default arrows with custom ones (direction can be 'left' or 'right')
62 | renderArrow: PropTypes.func,
63 | // Provide custom day rendering component
64 | dayComponent: PropTypes.any,
65 | // Month format in calendar title. Formatting values: http://arshaw.com/xdate/#Formatting
66 | monthFormat: PropTypes.string,
67 | // Disables changing month when click on days of other months (when hideExtraDays is false). Default = false
68 | disableMonthChange: PropTypes.bool,
69 | // Hide day names. Default = false
70 | hideDayNames: PropTypes.bool,
71 | // Disable days by default. Default = false
72 | disabledByDefault: PropTypes.bool,
73 | // Show week numbers. Default = false
74 | showWeekNumbers: PropTypes.bool,
75 | // Handler which gets executed when press arrow icon left. It receive a callback can go back month
76 | onPressArrowLeft: PropTypes.func,
77 | // Handler which gets executed when press arrow icon left. It receive a callback can go next month
78 | onPressArrowRight: PropTypes.func
79 | };
80 |
81 | constructor(props) {
82 | super(props);
83 | this.style = styleConstructor(this.props.theme);
84 | let currentMonth;
85 | if (props.current) {
86 | currentMonth = parseDate(props.current);
87 | } else {
88 | currentMonth = XDate();
89 | }
90 | this.state = {
91 | currentMonth
92 | };
93 |
94 | this.updateMonth = this.updateMonth.bind(this);
95 | this.addMonth = this.addMonth.bind(this);
96 | this.pressDay = this.pressDay.bind(this);
97 | this.longPressDay = this.longPressDay.bind(this);
98 | this.shouldComponentUpdate = shouldComponentUpdate;
99 | }
100 |
101 | componentWillReceiveProps(nextProps) {
102 | const current= parseDate(nextProps.current);
103 | if (current && current.toString('yyyy MM') !== this.state.currentMonth.toString('yyyy MM')) {
104 | this.setState({
105 | currentMonth: current.clone()
106 | });
107 | }
108 | }
109 |
110 | updateMonth(day, doNotTriggerListeners) {
111 | if (day.toString('yyyy MM') === this.state.currentMonth.toString('yyyy MM')) {
112 | return;
113 | }
114 | this.setState({
115 | currentMonth: day.clone()
116 | }, () => {
117 | if (!doNotTriggerListeners) {
118 | const currMont = this.state.currentMonth.clone();
119 | if (this.props.onMonthChange) {
120 | this.props.onMonthChange(xdateToData(currMont));
121 | }
122 | if (this.props.onVisibleMonthsChange) {
123 | this.props.onVisibleMonthsChange([xdateToData(currMont)]);
124 | }
125 | }
126 | });
127 | }
128 |
129 | _handleDayInteraction(date, interaction) {
130 | const day = parseDate(date);
131 | const minDate = parseDate(this.props.minDate);
132 | const maxDate = parseDate(this.props.maxDate);
133 | if (!(minDate && !dateutils.isGTE(day, minDate)) && !(maxDate && !dateutils.isLTE(day, maxDate))) {
134 | const shouldUpdateMonth = this.props.disableMonthChange === undefined || !this.props.disableMonthChange;
135 | if (shouldUpdateMonth) {
136 | this.updateMonth(day);
137 | }
138 | if (interaction) {
139 | interaction(xdateToData(day));
140 | }
141 | }
142 | }
143 |
144 | pressDay(date) {
145 | this._handleDayInteraction(date, this.props.onDayPress);
146 | }
147 |
148 | longPressDay(date) {
149 | this._handleDayInteraction(date, this.props.onDayLongPress);
150 | }
151 |
152 | addMonth(count) {
153 | this.updateMonth(this.state.currentMonth.clone().addMonths(count, true));
154 | }
155 |
156 | renderDay(day, id) {
157 | const minDate = parseDate(this.props.minDate);
158 | const maxDate = parseDate(this.props.maxDate);
159 | let state = '';
160 | if (this.props.disabledByDefault) {
161 | state = 'disabled';
162 | } else if ((minDate && !dateutils.isGTE(day, minDate)) || (maxDate && !dateutils.isLTE(day, maxDate))) {
163 | state = 'disabled';
164 | } else if (!dateutils.sameMonth(day, this.state.currentMonth)) {
165 | state = 'disabled';
166 | } else if (dateutils.sameDate(day, XDate())) {
167 | state = 'today';
168 | }
169 | let dayComp;
170 | if (!dateutils.sameMonth(day, this.state.currentMonth) && this.props.hideExtraDays) {
171 | if (['period', 'multi-period'].includes(this.props.markingType)) {
172 | dayComp = ();
173 | } else {
174 | dayComp = ();
175 | }
176 | } else {
177 | const DayComp = this.getDayComponent();
178 | const date = day.getDate();
179 | dayComp = (
180 |
189 | {date}
190 |
191 | );
192 | }
193 | return dayComp;
194 | }
195 |
196 | getDayComponent() {
197 | if (this.props.dayComponent) {
198 | return this.props.dayComponent;
199 | }
200 |
201 | switch (this.props.markingType) {
202 | case 'period':
203 | return UnitDay;
204 | case 'multi-dot':
205 | return MultiDotDay;
206 | case 'multi-period':
207 | return MultiPeriodDay;
208 | case 'custom':
209 | return SingleDay;
210 | default:
211 | return Day;
212 | }
213 | }
214 |
215 | getDateMarking(day) {
216 | if (!this.props.markedDates) {
217 | return false;
218 | }
219 | const dates = this.props.markedDates[day.toString('yyyy-MM-dd')] || EmptyArray;
220 | if (dates.length || dates) {
221 | return dates;
222 | } else {
223 | return false;
224 | }
225 | }
226 |
227 | renderWeekNumber (weekNumber) {
228 | return {weekNumber};
229 | }
230 |
231 | renderWeek(days, id) {
232 | const week = [];
233 | days.forEach((day, id2) => {
234 | week.push(this.renderDay(day, id2));
235 | }, this);
236 |
237 | if (this.props.showWeekNumbers) {
238 | week.unshift(this.renderWeekNumber(days[days.length - 1].getWeek()));
239 | }
240 |
241 | return ({week});
242 | }
243 |
244 | render() {
245 | const days = dateutils.page(this.state.currentMonth, this.props.firstDay);
246 | const weeks = [];
247 | while (days.length) {
248 | weeks.push(this.renderWeek(days.splice(0, 7), weeks.length));
249 | }
250 | let indicator;
251 | const current = parseDate(this.props.current);
252 | if (current) {
253 | const lastMonthOfDay = current.clone().addMonths(1, true).setDate(1).addDays(-1).toString('yyyy-MM-dd');
254 | if (this.props.displayLoadingIndicator &&
255 | !(this.props.markedDates && this.props.markedDates[lastMonthOfDay])) {
256 | indicator = true;
257 | }
258 | }
259 | return (
260 |
261 |
275 | {weeks}
276 | );
277 | }
278 | }
279 |
280 | export default Calendar;
281 |
--------------------------------------------------------------------------------
/src/calendar/style.js:
--------------------------------------------------------------------------------
1 | import {StyleSheet} from 'react-native';
2 | import * as defaultStyle from '../style';
3 |
4 | const STYLESHEET_ID = 'stylesheet.calendar.main';
5 |
6 | export default function getStyle(theme={}) {
7 | const appStyle = {...defaultStyle, ...theme};
8 | return StyleSheet.create({
9 | container: {
10 | paddingLeft: 5,
11 | paddingRight: 5,
12 | backgroundColor: appStyle.calendarBackground
13 | },
14 | monthView: {
15 | backgroundColor: appStyle.calendarBackground
16 | },
17 | week: {
18 | marginTop: 7,
19 | marginBottom: 7,
20 | flexDirection: 'row',
21 | justifyContent: 'space-around'
22 | },
23 | dayContainer: {
24 | width: 32
25 | },
26 | ...(theme[STYLESHEET_ID] || {})
27 | });
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/src/calendar/updater.js:
--------------------------------------------------------------------------------
1 | import {parseDate} from '../interface';
2 |
3 | export default function shouldComponentUpdate(nextProps, nextState) {
4 | let shouldUpdate = (nextProps.selected || []).reduce((prev, next, i) => {
5 | const currentSelected = (this.props.selected || [])[i];
6 | if (!currentSelected || !next || parseDate(currentSelected).getTime() !== parseDate(next).getTime()) {
7 | return {
8 | update: true,
9 | field: 'selected'
10 | };
11 | }
12 | return prev;
13 | }, {update: false});
14 |
15 | shouldUpdate = ['markedDates', 'hideExtraDays'].reduce((prev, next) => {
16 | if (!prev.update && nextProps[next] !== this.props[next]) {
17 | return {
18 | update: true,
19 | field: next
20 | };
21 | }
22 | return prev;
23 | }, shouldUpdate);
24 |
25 | shouldUpdate = ['minDate', 'maxDate', 'current'].reduce((prev, next) => {
26 | const prevDate = parseDate(this.props[next]);
27 | const nextDate = parseDate(nextProps[next]);
28 | if (prev.update) {
29 | return prev;
30 | } else if (prevDate !== nextDate) {
31 | if (prevDate && nextDate && prevDate.getTime() === nextDate.getTime()) {
32 | return prev;
33 | } else {
34 | return {
35 | update: true,
36 | field: next
37 | };
38 | }
39 | }
40 | return prev;
41 | }, shouldUpdate);
42 |
43 | if (nextState.currentMonth !== this.state.currentMonth) {
44 | shouldUpdate = {
45 | update: true,
46 | field: 'current'
47 | };
48 | }
49 | //console.log(shouldUpdate.field, shouldUpdate.update);
50 | return shouldUpdate.update;
51 | }
52 |
--------------------------------------------------------------------------------
/src/component-updater.js:
--------------------------------------------------------------------------------
1 | const get = require('lodash.get');
2 | const isEqual = require('lodash.isequal');
3 |
4 | function shouldUpdate(a, b, paths) {
5 | for (let i = 0; i < paths.length; i++) {
6 | const equals = isEqual(get(a, paths[i]), get(b, paths[i]));
7 | if (!equals) {
8 | return true;
9 | }
10 | }
11 | return false;
12 | }
13 |
14 | module.exports = {
15 | shouldUpdate
16 | };
17 |
--------------------------------------------------------------------------------
/src/component-updater.spec.js:
--------------------------------------------------------------------------------
1 | const {shouldUpdate} = require('./component-updater');
2 |
3 | describe('component updater', () => {
4 | it('should return true if two different objects are provided with same path', async () => {
5 | const a = {details: 'whoa'};
6 | const b = {details: 'whoax'};
7 | const paths = ['details'];
8 |
9 | expect(shouldUpdate(a, b, paths)).toEqual(true);
10 | });
11 |
12 | it('should return false if two same objects are provided with same path', async () => {
13 | const a = {details: 'whoa'};
14 | const b = {details: 'whoa'};
15 | const paths = ['details'];
16 |
17 | expect(shouldUpdate(a, b, paths)).toEqual(false);
18 | });
19 |
20 | it('should return true if two different deep objects are provided with same path', async () => {
21 | const a = {details: {x: {y: 1}}};
22 | const b = {details: {x: {y: 2}}};
23 | const paths = ['details'];
24 |
25 | expect(shouldUpdate(a, b, paths)).toEqual(true);
26 | });
27 |
28 | it('should return false if two same deep objects are provided with same path', async () => {
29 | const a = {details: {x: {y: 1}}};
30 | const b = {details: {x: {y: 1}}};
31 | const paths = ['details'];
32 |
33 | expect(shouldUpdate(a, b, paths)).toEqual(false);
34 | });
35 |
36 | it('should return false if several same deep objects are provided with same path', async () => {
37 | const a = {details: {x: {y: 1}}, details2: {x: {y: 2}}, porage: 'yes'};
38 | const b = {details: {x: {y: 1}}, details2: {x: {y: 2}}, porage: 'yes'};
39 | const paths = ['details', 'details2', 'porage'];
40 |
41 | expect(shouldUpdate(a, b, paths)).toEqual(false);
42 | });
43 |
44 | it('should return true if several different deep objects are provided with same path', async () => {
45 | const a = {details: {x: {y: 1}}, details2: {x: {y: 2}}, porage: 'yes'};
46 | const b = {details: {x: {y: 1}}, details2: {x: {y: 2}}, porage: 'no'};
47 | const paths = ['details', 'details2', 'porage'];
48 |
49 | expect(shouldUpdate(a, b, paths)).toEqual(true);
50 | });
51 |
52 | it('should return true if two different deep props of objects are provided with same path', async () => {
53 | const a = {details: {x: {y: 1}}, details2: {x: {y: 2}}, porage: 'yes'};
54 | const b = {details: {x: {y: 2}}, details2: {x: {y: 2}}, porage: 'yes'};
55 | const paths = ['details.x.y', 'details2', 'porage'];
56 |
57 | expect(shouldUpdate(a, b, paths)).toEqual(true);
58 | });
59 |
60 | it('should return false if two same deep props of objects are provided with same path', async () => {
61 | const a = {details: {x: {y: 1}, y: '1'}, details2: {x: {y: 2}}, porage: 'yes'};
62 | const b = {details: {x: {y: 1}}, details2: {x: {y: 2}}, porage: 'yes'};
63 | const paths = ['details.x.y', 'details2', 'porage'];
64 |
65 | expect(shouldUpdate(a, b, paths)).toEqual(false);
66 | });
67 | });
68 |
--------------------------------------------------------------------------------
/src/dateutils.js:
--------------------------------------------------------------------------------
1 | const XDate = require('xdate');
2 |
3 | function sameMonth(a, b) {
4 | return a instanceof XDate && b instanceof XDate &&
5 | a.getFullYear() === b.getFullYear() &&
6 | a.getMonth() === b.getMonth();
7 | }
8 |
9 | function sameDate(a, b) {
10 | return a instanceof XDate && b instanceof XDate &&
11 | a.getFullYear() === b.getFullYear() &&
12 | a.getMonth() === b.getMonth() &&
13 | a.getDate() === b.getDate();
14 | }
15 |
16 | function isGTE(a, b) {
17 | return b.diffDays(a) > -1;
18 | }
19 |
20 | function isLTE(a, b) {
21 | return a.diffDays(b) > -1;
22 | }
23 |
24 | function fromTo(a, b) {
25 | const days = [];
26 | let from = +a, to = +b;
27 | for (; from <= to; from = new XDate(from, true).addDays(1).getTime()) {
28 | days.push(new XDate(from, true));
29 | }
30 | return days;
31 | }
32 |
33 | function month(xd) {
34 | const year = xd.getFullYear(), month = xd.getMonth();
35 | const days = new Date(year, month + 1, 0).getDate();
36 |
37 | const firstDay = new XDate(year, month, 1, 0, 0, 0, true);
38 | const lastDay = new XDate(year, month, days, 0, 0, 0, true);
39 |
40 | return fromTo(firstDay, lastDay);
41 | }
42 |
43 | function weekDayNames(firstDayOfWeek = 0) {
44 | let weekDaysNames = XDate.locales[XDate.defaultLocale].dayNamesShort;
45 | const dayShift = firstDayOfWeek % 7;
46 | if (dayShift) {
47 | weekDaysNames = weekDaysNames.slice(dayShift).concat(weekDaysNames.slice(0, dayShift));
48 | }
49 | return weekDaysNames;
50 | }
51 |
52 | function page(xd, firstDayOfWeek) {
53 | const days = month(xd);
54 | let before = [], after = [];
55 |
56 | const fdow = ((7 + firstDayOfWeek) % 7) || 7;
57 | const ldow = (fdow + 6) % 7;
58 |
59 | firstDayOfWeek = firstDayOfWeek || 0;
60 |
61 | const from = days[0].clone();
62 | if (from.getDay() !== fdow) {
63 | from.addDays(-(from.getDay() + 7 - fdow) % 7);
64 | }
65 |
66 | const to = days[days.length - 1].clone();
67 | const day = to.getDay();
68 | if (day !== ldow) {
69 | to.addDays((ldow + 7 - day) % 7);
70 | }
71 |
72 | if (isLTE(from, days[0])) {
73 | before = fromTo(from, days[0]);
74 | }
75 |
76 | if (isGTE(to, days[days.length - 1])) {
77 | after = fromTo(days[days.length - 1], to);
78 | }
79 |
80 | return before.concat(days.slice(1, days.length - 1), after);
81 | }
82 |
83 | module.exports = {
84 | weekDayNames,
85 | sameMonth,
86 | sameDate,
87 | month,
88 | page,
89 | fromTo,
90 | isLTE,
91 | isGTE
92 | };
93 |
--------------------------------------------------------------------------------
/src/dateutils.spec.js:
--------------------------------------------------------------------------------
1 | const XDate = require('xdate');
2 | const dateutils = require('./dateutils');
3 |
4 | describe('dateutils', function () {
5 | describe('sameMonth()', function () {
6 | it('2014-01-01 === 2014-01-10', function () {
7 | const a = XDate(2014, 0, 1, true);
8 | const b = XDate(2014, 0, 10, true);
9 | expect(dateutils.sameMonth(a, b)).toEqual(true);
10 | });
11 | it('for non-XDate instances is false', function () {
12 | expect(dateutils.sameMonth('a', 'b')).toEqual(false);
13 | expect(dateutils.sameMonth(123, 345)).toEqual(false);
14 | expect(dateutils.sameMonth(null, false)).toEqual(false);
15 |
16 | const a = XDate(2014, 0, 1, true);
17 | const b = XDate(2014, 0, 10, true);
18 | expect(dateutils.sameMonth(a, undefined)).toEqual(false);
19 | expect(dateutils.sameMonth(null, b)).toEqual(false);
20 | });
21 | });
22 |
23 | describe('isLTE()', function () {
24 | it('2014-01-20 >= 2013-12-31', function () {
25 | const a = XDate(2013, 12, 31);
26 | const b = XDate(2014, 1, 20);
27 | expect(dateutils.isLTE(a, b)).toBe(true);
28 | });
29 |
30 | it('2014-10-20 >= 2014-10-19', function () {
31 | const a = XDate(2014, 10, 19);
32 | const b = XDate(2014, 10, 20);
33 | expect(dateutils.isLTE(a, b)).toBe(true);
34 | });
35 |
36 | it('2014-10-20 >= 2014-09-30', function () {
37 | const a = XDate(2014, 9, 30);
38 | const b = XDate(2014, 10, 20);
39 | expect(dateutils.isLTE(a, b)).toBe(true);
40 | });
41 |
42 | it('works for dates that differ by less than a day', function () {
43 | const a = XDate(2014, 9, 30, 0, 1, 0);
44 | const b = XDate(2014, 9, 30, 1, 0, 1);
45 | expect(dateutils.isLTE(a, b)).toBe(true);
46 | expect(dateutils.isLTE(b, a)).toBe(true);
47 | });
48 | });
49 |
50 | describe('isGTE()', function () {
51 | it('2014-01-20 >= 2013-12-31', function () {
52 | const a = XDate(2013, 12, 31);
53 | const b = XDate(2014, 1, 20);
54 | expect(dateutils.isGTE(b, a)).toBe(true);
55 | });
56 |
57 | it('2014-10-20 >= 2014-10-19', function () {
58 | const a = XDate(2014, 10, 19);
59 | const b = XDate(2014, 10, 20);
60 | expect(dateutils.isGTE(b, a)).toBe(true);
61 | });
62 |
63 | it('2014-10-20 >= 2014-09-30', function () {
64 | const a = XDate(2014, 9, 30);
65 | const b = XDate(2014, 10, 20);
66 | expect(dateutils.isGTE(b, a)).toBe(true);
67 | });
68 |
69 | it('works for dates that differ by less than a day', function () {
70 | const a = XDate(2014, 9, 30, 0, 1, 0);
71 | const b = XDate(2014, 9, 30, 1, 0, 1);
72 | expect(dateutils.isGTE(a, b)).toBe(true);
73 | expect(dateutils.isGTE(b, a)).toBe(true);
74 | });
75 | });
76 |
77 | describe('month()', function () {
78 | it('2014 May', function () {
79 | const days = dateutils.month(XDate(2014, 4, 1));
80 | expect(days.length).toBe(31);
81 | });
82 |
83 | it('2014 August', function () {
84 | const days = dateutils.month(XDate(2014, 7, 1));
85 | expect(days.length).toBe(31);
86 | });
87 | });
88 |
89 | describe('page()', function () {
90 | it('2014 March', function () {
91 | const days = dateutils.page(XDate(2014, 2, 23, true));
92 | expect(days.length).toBe(42);
93 | expect(days[0].toString())
94 | .toBe(XDate(2014, 1, 23, 0, 0, 0, true).toString());
95 | expect(days[days.length - 1].toString())
96 | .toBe(XDate(2014, 3, 5, 0, 0, 0, true).toString());
97 | });
98 |
99 | it('2014 May', function () {
100 | const days = dateutils.page(XDate(2014, 4, 23));
101 | expect(days.length).toBe(35);
102 | });
103 |
104 | it('2014 June', function () {
105 | const days = dateutils.page(XDate(2014, 5, 23));
106 | expect(days.length).toBe(35);
107 | });
108 |
109 | it('2014 August', function () {
110 | const days = dateutils.page(XDate(2014, 7, 23));
111 | expect(days.length).toBe(42);
112 | });
113 |
114 | it('2014 October', function () {
115 | const days = dateutils.page(XDate(2014, 9, 21));
116 | expect(days.length).toBe(35);
117 | });
118 |
119 | it('has all days in ascending order', function () {
120 | let days, i, len;
121 |
122 | days = dateutils.page(XDate(2014, 2, 1));
123 | for (i = 0, len = days.length - 1; i < len; i++) {
124 | expect(days[i].diffDays(days[i + 1])).toBe(1);
125 | }
126 | days = dateutils.page(XDate(2014, 9, 1));
127 | for (i = 0, len = days.length - 1; i < len; i++) {
128 | expect(days[i].diffDays(days[i + 1])).toBe(1);
129 | }
130 | });
131 | });
132 |
133 | });
134 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export { default as Calendar } from './calendar';
2 | export { default as CalendarList } from './calendar-list';
3 | export { default as Agenda } from './agenda';
4 | export { default as LocaleConfig } from 'xdate';
5 |
--------------------------------------------------------------------------------
/src/input.js:
--------------------------------------------------------------------------------
1 | export class VelocityTracker {
2 | constructor() {
3 | this.history = [];
4 | this.lastPosition = undefined;
5 | this.lastTimestamp = undefined;
6 | }
7 |
8 | add(position) {
9 | const timestamp = new Date().valueOf();
10 | if (this.lastPosition && timestamp > this.lastTimestamp) {
11 | const diff = position - this.lastPosition;
12 | if (diff > 0.001 || diff < -0.001) {
13 | this.history.push(diff / (timestamp - this.lastTimestamp));
14 | }
15 | }
16 | this.lastPosition = position;
17 | this.lastTimestamp = timestamp;
18 | }
19 |
20 | estimateSpeed() {
21 | const finalTrend = this.history.slice(-3);
22 | const sum = finalTrend.reduce((r, v) => r + v, 0);
23 | return sum / finalTrend.length;
24 | }
25 |
26 | reset() {
27 | this.history = [];
28 | this.lastPosition = undefined;
29 | this.lastTimestamp = undefined;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/interface.js:
--------------------------------------------------------------------------------
1 | const XDate = require('xdate');
2 |
3 | function padNumber(n) {
4 | if (n < 10) {
5 | return '0' + n;
6 | }
7 | return n;
8 | }
9 |
10 | function xdateToData(xdate) {
11 | const dateString = xdate.toString('yyyy-MM-dd');
12 | return {
13 | year: xdate.getFullYear(),
14 | month: xdate.getMonth() + 1,
15 | day: xdate.getDate(),
16 | timestamp: XDate(dateString, true).getTime(),
17 | dateString: dateString
18 | };
19 | }
20 |
21 | function parseDate(d) {
22 | if (!d) {
23 | return;
24 | } else if (d.timestamp) { // conventional data timestamp
25 | return XDate(d.timestamp, true);
26 | } else if (d instanceof XDate) { // xdate
27 | return XDate(d.toString('yyyy-MM-dd'), true);
28 | } else if (d.getTime) { // javascript date
29 | const dateString = d.getFullYear() + '-' + padNumber((d.getMonth() + 1)) + '-' + padNumber(d.getDate());
30 | return XDate(dateString, true);
31 | } else if (d.year) {
32 | const dateString = d.year + '-' + padNumber(d.month) + '-' + padNumber(d.day);
33 | return XDate(dateString, true);
34 | } else if (d) { // timestamp nuber or date formatted as string
35 | return XDate(d, true);
36 | }
37 | }
38 |
39 | module.exports = {
40 | xdateToData,
41 | parseDate
42 | };
43 |
44 |
--------------------------------------------------------------------------------
/src/interface.spec.js:
--------------------------------------------------------------------------------
1 | const iface = require('./interface');
2 | const XDate = require('xdate');
3 |
4 | describe('calendar interface', () => {
5 | describe('input', () => {
6 | it('should return undefined if date is undefined', () => {
7 | const date = iface.parseDate();
8 | expect(date).toBe(undefined);
9 | });
10 |
11 | it('should accept UTC timestamp as argument', () => {
12 | const date = iface.parseDate(1479832134398);
13 | expect(date.getTime()).toEqual(1479832134398);
14 | expect(date.getTimezoneOffset()).toEqual(0);
15 | });
16 |
17 | it('should accept datestring as argument', () => {
18 | const date = iface.parseDate('2012-03-16');
19 | expect(date.toString('yyyy-MM-dd')).toEqual('2012-03-16');
20 | expect(date.getTimezoneOffset()).toEqual(0);
21 | });
22 |
23 | it('should expect object with UTC timestamp as argument', () => {
24 | const date = iface.parseDate({timestamp: 1479832134398});
25 | expect(date.getTime()).toEqual(1479832134398);
26 | expect(date.getTimezoneOffset()).toEqual(0);
27 | });
28 |
29 | it('should accept XDate as argument', () => {
30 | const testDate = XDate('2016-11-22 00:00:00+3');
31 | expect(testDate.toISOString()).toEqual('2016-11-21T21:00:00Z');
32 | const time = 1479772800000;
33 | expect(XDate(time, true).toISOString()).toEqual('2016-11-22T00:00:00Z');
34 | });
35 |
36 | it('should accept Date as argument', () => {
37 | const testDate = new Date(2015, 5, 5, 12, 0);
38 | const date = iface.parseDate(testDate);
39 | expect(date.toString('yyyy-MM-dd')).toEqual('2015-06-05');
40 | });
41 |
42 | it('should accept data as argument', () => {
43 | const testDate = {
44 | year: 2015,
45 | month: 5,
46 | day: 6
47 | };
48 | const date = iface.parseDate(testDate);
49 | expect(date.toString('yyyy-MM-dd')).toEqual('2015-05-06');
50 | });
51 | });
52 |
53 | describe('output', () => {
54 | it('should convert xdate to data', () => {
55 | const time = 1479772800000;
56 | const testDate = XDate(time, true);
57 | expect((testDate).toISOString()).toEqual('2016-11-22T00:00:00Z');
58 | const data = iface.xdateToData(testDate);
59 | expect(data).toEqual({
60 | year: 2016,
61 | month: 11,
62 | day: 22,
63 | timestamp: 1479772800000,
64 | dateString: '2016-11-22'
65 | });
66 | });
67 | });
68 | });
69 |
--------------------------------------------------------------------------------
/src/style.js:
--------------------------------------------------------------------------------
1 | import {Platform} from 'react-native';
2 |
3 | export const foregroundColor = '#ffffff';
4 | export const backgroundColor = '#f4f4f4';
5 | export const separatorColor = '#e8e9ec';
6 |
7 | export const processedColor = '#a7e0a3';
8 | export const processingColor = '#ffce5c';
9 | export const failedColor = 'rgba(246, 126, 126,1)';
10 |
11 | export const textDefaultColor = '#2d4150';
12 | export const textColor = '#43515c';
13 | export const textLinkColor = '#00adf5';
14 | export const textSecondaryColor = '#7a92a5';
15 |
16 | export const textDayFontFamily = 'System';
17 | export const textMonthFontFamily = 'System';
18 | export const textDayHeaderFontFamily = 'System';
19 |
20 | export const textMonthFontWeight = '300';
21 |
22 | export const textDayFontSize = 16;
23 | export const textMonthFontSize = 16;
24 | export const textDayHeaderFontSize = 13;
25 |
26 | export const calendarBackground = foregroundColor;
27 | export const textSectionTitleColor = '#b6c1cd';
28 | export const selectedDayBackgroundColor = textLinkColor;
29 | export const selectedDayTextColor = foregroundColor;
30 | export const todayBackgroundColor = undefined;
31 | export const todayTextColor = textLinkColor;
32 | export const dayTextColor = textDefaultColor;
33 | export const textDisabledColor = '#d9e1e8';
34 | export const dotColor = textLinkColor;
35 | export const selectedDotColor = foregroundColor;
36 | export const arrowColor = textLinkColor;
37 | export const monthTextColor = textDefaultColor;
38 | export const agendaDayTextColor = '#7a92a5';
39 | export const agendaDayNumColor = '#7a92a5';
40 | export const agendaTodayColor = textLinkColor;
41 | export const agendaKnobColor = Platform.OS === 'ios' ? '#f2F4f5' : '#4ac4f7';
42 |
--------------------------------------------------------------------------------
/src/testIDs.js:
--------------------------------------------------------------------------------
1 | const PREFIX = 'native.calendar';
2 |
3 | module.exports = {
4 | CHANGE_MONTH_LEFT_ARROW: `${PREFIX}.CHANGE_MONTH_LEFT_ARROW`,
5 | CHANGE_MONTH_RIGHT_ARROW: `${PREFIX}.CHANGE_MONTH_RIGHT_ARROW`
6 | };
--------------------------------------------------------------------------------