Skip to content

Commit d91e5a4

Browse files
committed
horizontal calendar list and few twicks
1 parent 7994644 commit d91e5a4

File tree

11 files changed

+246
-11
lines changed

11 files changed

+246
-11
lines changed

README.md

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Event handler callbacks are called with `calendar objects` like this:
3636

3737
Parameters that require date types accept YYYY-MM-DD formated datestrings (in gregorian), JavaScript date objects, `calendar objects` and UTC timestamps.
3838

39-
Calendars can be localized by adding custom locales using `Moment's i18n` object:
39+
Calendars can be localized by adding custom locales using `Moment's i18n` functions:
4040

4141
```javascript
4242
import Moment from 'moment';
@@ -165,11 +165,47 @@ Period marking
165165
'2012-05-23': {selected: true, endingDay: true, color: 'green', textColor: 'gray'},
166166
'2012-05-04': {disabled: true, startingDay: true, color: 'green', endingDay: true}
167167
}}
168-
// Date marking style [simple/period/multi-dot]. Default = 'simple'
168+
// Date marking style [simple/period/multi-dot/custom]. Default = 'simple'
169169
markingType={'period'}
170170
/>
171171
```
172172

173+
Custom marking allows you to customize each marker with custom styles.
174+
175+
<kbd>
176+
<img height=50 src="https://github.com/rghorbani/react-native-general-calendars/blob/master/demo/custom.png?raw=true">
177+
</kbd>
178+
179+
```javascript
180+
<Calendar
181+
// Date marking style [simple/period/multi-dot/single]. Default = 'simple'
182+
markingType={'custom'}
183+
markedDates={{
184+
'2018-03-28': {
185+
customStyles: {
186+
container: {
187+
backgroundColor: 'green',
188+
},
189+
text: {
190+
color: 'black',
191+
fontWeight: 'bold'
192+
},
193+
},
194+
},
195+
'2018-03-29': {
196+
customStyles: {
197+
container: {
198+
backgroundColor: 'white',
199+
elevation: 2
200+
},
201+
text: {
202+
color: 'blue',
203+
},
204+
}
205+
}}}
206+
/>
207+
```
208+
173209
Keep in mind that different marking types are not compatible. You can use just one marking style for calendar.
174210

175211
#### Displaying data loading indicator
@@ -207,6 +243,7 @@ The loading indicator next to month name will be displayed if `<Calendar />` has
207243
textDayFontFamily: 'monospace',
208244
textMonthFontFamily: 'monospace',
209245
textDayHeaderFontFamily: 'monospace',
246+
textMonthFontWeight: 'bold',
210247
textDayFontSize: 16,
211248
textMonthFontSize: 16,
212249
textDayHeaderFontSize: 16
@@ -287,6 +324,27 @@ If you implement an awesome day component please make a PR so that other people
287324
/>
288325
```
289326

327+
#### Horizontal CalendarList
328+
329+
<kbd>
330+
<img src="https://github.com/rghorbani/react-native-general-calendars/blob/master/demo/horizontal-calendar-list.gif?raw=true">
331+
</kbd>
332+
333+
You can also make the `CalendarList` scroll horizontally. To do that you need to pass specific props to the `CalendarList`:
334+
335+
```javascript
336+
<CalendarList
337+
// Enable horizontal scrolling, default = false
338+
horizontal={true}
339+
// Enable paging on horizontal, default = false
340+
pagingEnabled={true}
341+
// Set custom calendarWidth.
342+
calendarWidth={320}
343+
...calendarListParams
344+
...calendarParams
345+
/>
346+
```
347+
290348
### Agenda
291349

292350
Coming soon

demo/custom.png

4.62 KB
Loading

demo/horizontal-calendar-list.gif

3.11 MB
Loading

demo/marking5.png

4.33 KB
Loading

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-general-calendars",
3-
"version": "1.2.3",
3+
"version": "1.3.0",
44
"description": "React Native Calendar Components with support of Gregorian & Jalaali Calendars",
55
"main": "src/index.js",
66
"scripts": {

src/calendar-list/index.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,26 @@ const React = require('react');
1010
const PropTypes = require('prop-types');
1111
const Moment = require('moment');
1212
const jMoment = require('moment-jalaali');
13-
const { FlatList, Platform, StyleSheet } = require('react-native');
13+
const { Dimensions, FlatList, Platform, StyleSheet } = require('react-native');
1414

1515
const CalendarListItem = require('./item');
1616
const Calendar = require('../calendar');
1717
const defaultStyle = require('../style');
1818
const dateutils = require('../dateutils');
1919
const { xdateToData, parseDate } = require('../interface');
2020

21+
const { width } = Dimensions.get('window');
22+
2123
class CalendarList extends React.Component {
2224
static propTypes = {
2325
...Calendar.propTypes,
2426

27+
// Whether the scroll is horizontal
28+
horizontal: PropTypes.bool,
29+
30+
// Used when calendar scroll is horizontal, default is device width, pagination should be disabled
31+
calendarWidth: PropTypes.number,
32+
2533
// hight of each calendar. Default = 360
2634
calendarHeight: PropTypes.number,
2735

@@ -43,12 +51,14 @@ class CalendarList extends React.Component {
4351

4452
static defaultProps = {
4553
type: 'gregorian',
54+
calendarWidth: width,
4655
calendarHeight: 360,
4756
pastScrollRange: 50,
4857
futureScrollRange: 50,
4958
showScrollIndicator: false,
5059
scrollEnabled: true,
5160
scrollsToTop: false,
61+
removeClippedSubviews: Platform.OS === 'android' ? false : true,
5262
};
5363

5464
constructor(props) {
@@ -91,9 +101,9 @@ class CalendarList extends React.Component {
91101
initialized: false,
92102
};
93103

94-
this.getItemLayout = this.getItemLayout.bind(this);
95104
this.onViewableItemsChangedBound = this.onViewableItemsChanged.bind(this);
96105
this.renderCalendar = this.renderCalendar.bind(this);
106+
this.getItemLayout = this.getItemLayout.bind(this);
97107
}
98108

99109
scrollToDay(d, offset, animated) {
@@ -193,11 +203,11 @@ class CalendarList extends React.Component {
193203
}
194204

195205
renderCalendar({item}) {
196-
return (<CalendarListItem item={item} calendarHeight={this.props.calendarHeight} {...this.props} />);
206+
return (<CalendarListItem item={item} calendarHeight={this.props.calendarHeight} calendarWidth={this.props.horizontal ? this.props.calendarWidth : undefined} {...this.props} />);
197207
}
198208

199209
getItemLayout(data, index) {
200-
return {length: this.props.calendarHeight, offset: this.props.calendarHeight * index, index};
210+
return {length: this.props.horizontal ? this.props.calendarWidth : this.props.calendarHeight, offset: (this.props.horizontal ? this.props.calendarWidth : this.props.calendarHeight) * index, index};
201211
}
202212

203213
getMonthIndex(month) {
@@ -215,13 +225,16 @@ class CalendarList extends React.Component {
215225
<FlatList
216226
ref={(c) => this.listView = c}
217227
style={[this.style.container, this.props.style]}
218-
initialListSize={this.props.pastScrollRange * this.props.futureScrollRange + 1}
228+
initialListSize={this.props.pastScrollRange + this.props.futureScrollRange + 1}
219229
data={this.state.rows}
220-
removeClippedSubviews={Platform.OS === 'android' ? false : true}
230+
removeClippedSubviews={this.props.removeClippedSubviews}
221231
pageSize={1}
232+
horizontal={this.props.horizontal || false}
233+
pagingEnabled={this.props.pagingEnabled}
222234
onViewableItemsChanged={this.onViewableItemsChangedBound}
223235
renderItem={this.renderCalendar}
224236
showsVerticalScrollIndicator={this.props.showScrollIndicator}
237+
showsHorizontalScrollIndicator={this.props.showScrollIndicator}
225238
scrollEnabled={this.props.scrollEnabled}
226239
keyExtractor={(item, index) => String(index)}
227240
initialScrollIndex={this.state.openDate ? this.getMonthIndex(this.state.openDate) : false}

src/calendar/day/basic/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class Day extends React.Component {
5656
markingChanged = (!(
5757
this.props.marking.marked === nextProps.marking.marked
5858
&& this.props.marking.selected === nextProps.marking.selected
59+
&& this.props.marking.selectedColor === nextProps.marking.selectedColor
5960
&& this.props.marking.dotColor === nextProps.marking.dotColor
6061
&& this.props.marking.disabled === nextProps.marking.disabled));
6162
} else {

src/calendar/day/custom/index.js

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/**
2+
* Copyright 2016 Reza (github.com/rghorbani).
3+
*
4+
* @flow
5+
*/
6+
7+
'use strict';
8+
9+
const React = require('react');
10+
const PropTypes = require('prop-types');
11+
const { Platform, StyleSheet, Text, TouchableOpacity } = require('react-native');
12+
13+
const defaultStyle = require('../../../style');
14+
15+
class Day extends React.Component {
16+
static propTypes = {
17+
// TODO: disabled props should be removed
18+
state: PropTypes.oneOf(['selected', 'disabled', 'today', '']),
19+
20+
// Specify theme properties to override specific styles for calendar parts. Default = {}
21+
theme: PropTypes.object,
22+
marking: PropTypes.any,
23+
onPress: PropTypes.func,
24+
date: PropTypes.object
25+
};
26+
27+
constructor(props) {
28+
super(props);
29+
this.style = styleConstructor(props.theme);
30+
this.onDayPress = this.onDayPress.bind(this);
31+
this.onDayLongPress = this.onDayLongPress.bind(this);
32+
}
33+
34+
onDayPress() {
35+
this.props.onPress(this.props.date);
36+
}
37+
onDayLongPress() {
38+
this.props.onLongPress(this.props.date);
39+
}
40+
41+
shouldComponentUpdate(nextProps) {
42+
const changed = ['state', 'children', 'marking', 'onPress'].reduce((prev, next) => {
43+
if (prev) {
44+
return prev;
45+
} else if (nextProps[next] !== this.props[next]) {
46+
return next;
47+
}
48+
return prev;
49+
}, false);
50+
if (changed === 'marking') {
51+
let markingChanged = false;
52+
if (this.props.marking && nextProps.marking) {
53+
markingChanged = (!(
54+
this.props.marking.marked === nextProps.marking.marked
55+
&& this.props.marking.selected === nextProps.marking.selected
56+
&& this.props.marking.disabled === nextProps.marking.disabled));
57+
} else {
58+
markingChanged = true;
59+
}
60+
// console.log('marking changed', markingChanged);
61+
return markingChanged;
62+
} else {
63+
// console.log('changed', changed);
64+
return !!changed;
65+
}
66+
}
67+
68+
render() {
69+
let containerStyle = [this.style.base];
70+
let textStyle = [this.style.text];
71+
72+
let marking = this.props.marking || {};
73+
if (marking && marking.constructor === Array && marking.length) {
74+
marking = {
75+
marking: true
76+
};
77+
}
78+
const isDisabled = typeof marking.disabled !== 'undefined' ? marking.disabled : this.props.state === 'disabled';
79+
80+
if (marking.selected) {
81+
containerStyle.push(this.style.selected);
82+
} else if (isDisabled) {
83+
textStyle.push(this.style.disabledText);
84+
} else if (this.props.state === 'today') {
85+
textStyle.push(this.style.todayText);
86+
}
87+
88+
if (marking.customStyles && typeof marking.customStyles === 'object') {
89+
const styles = marking.customStyles;
90+
if (styles.container) {
91+
if (styles.container.borderRadius === undefined) {
92+
styles.container.borderRadius = 16;
93+
}
94+
containerStyle.push(styles.container);
95+
}
96+
if (styles.text) {
97+
textStyle.push(styles.text);
98+
}
99+
}
100+
101+
return (
102+
<TouchableOpacity
103+
style={containerStyle}
104+
onPress={this.onDayPress}
105+
onLongPress={this.onDayLongPress}
106+
activeOpacity={marking.activeOpacity}
107+
disabled={marking.disableTouchEvent}
108+
>
109+
<Text allowFontScaling={false} style={textStyle}>{String(this.props.children)}</Text>
110+
</TouchableOpacity>
111+
);
112+
}
113+
}
114+
115+
const STYLESHEET_ID = 'stylesheet.day.single';
116+
117+
function styleConstructor(theme = {}) {
118+
const appStyle = {...defaultStyle, ...theme};
119+
return StyleSheet.create({
120+
base: {
121+
width: 32,
122+
height: 32,
123+
alignItems: 'center'
124+
},
125+
text: {
126+
marginTop: Platform.OS === 'android' ? 4 : 6,
127+
fontSize: appStyle.textDayFontSize,
128+
fontFamily: appStyle.textDayFontFamily,
129+
fontWeight: '300',
130+
color: appStyle.dayTextColor,
131+
backgroundColor: 'rgba(255, 255, 255, 0)'
132+
},
133+
alignedText: {
134+
marginTop: Platform.OS === 'android' ? 4 : 6
135+
},
136+
selected: {
137+
backgroundColor: appStyle.selectedDayBackgroundColor,
138+
borderRadius: 16
139+
},
140+
todayText: {
141+
color: appStyle.todayTextColor
142+
},
143+
selectedText: {
144+
color: appStyle.selectedDayTextColor
145+
},
146+
disabledText: {
147+
color: appStyle.textDisabledColor
148+
},
149+
...(theme[STYLESHEET_ID] || {})
150+
});
151+
}
152+
153+
module.exports = Day;

src/calendar/header/index.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ class CalendarHeader extends React.Component {
9292
<TouchableOpacity
9393
onPress={this.onPressLeft}
9494
style={this.style.arrow}
95+
hitSlop={{left: 20, right: 20, top: 20, bottom: 20}}
9596
>
9697
{this.props.renderArrow
9798
? this.props.renderArrow('left')
@@ -102,7 +103,11 @@ class CalendarHeader extends React.Component {
102103
</TouchableOpacity>
103104
);
104105
rightArrow = (
105-
<TouchableOpacity onPress={this.onPressRight} style={this.style.arrow}>
106+
<TouchableOpacity
107+
onPress={this.onPressRight}
108+
style={this.style.arrow}
109+
hitSlop={{left: 20, right: 20, top: 20, bottom: 20}}
110+
>
106111
{this.props.renderArrow
107112
? this.props.renderArrow('right')
108113
: <Image
@@ -164,7 +169,7 @@ function styleConstructor(theme = {}, {rtl, type}) {
164169
monthText: {
165170
fontSize: appStyle.textMonthFontSize,
166171
fontFamily: appStyle.textMonthFontFamily,
167-
fontWeight: '300',
172+
fontWeight: appStyle.textMonthFontWeight,
168173
color: appStyle.monthTextColor,
169174
margin: 10
170175
},

src/calendar/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const { StyleSheet, View, ViewPropTypes } = require('react-native');
1515
const Day = require('./day/basic');
1616
const UnitDay = require('./day/period');
1717
const MultiDotDay = require('./day/multi-dot');
18+
const SingleDay = require('./day/custom');
1819
const CalendarHeader = require('./header');
1920
const shouldComponentUpdate = require('./updater');
2021
const dateutils = require('../dateutils');
@@ -245,6 +246,8 @@ class Calendar extends React.Component {
245246
return UnitDay;
246247
case 'multi-dot':
247248
return MultiDotDay;
249+
case 'custom':
250+
return SingleDay;
248251
default:
249252
return Day;
250253
}

0 commit comments

Comments
 (0)