Skip to content

Commit 810b15b

Browse files
committed
Responsively size calendar strip to container width.
See #14
1 parent 5799315 commit 810b15b

File tree

6 files changed

+151
-57
lines changed

6 files changed

+151
-57
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Easy to use and visually stunning calendar component for React Native.
44

5-
`<CalendarStrip>` is a React Native component designed to replace the standard date picker component. It works for both `iOS` and `Android` and in both `portrait` and `landscape` orientations!
5+
`<CalendarStrip>` is a React Native component designed to replace the standard date picker component. It supports `iOS` & `Android` and responsively sizes its height based on its container width. It gracefully resizes for `portrait` and `landscape` orientations and virtually all display resolutions.
66

77
![alt text](https://raw.githubusercontent.com/BugiDev/react-native-calendar-strip/master/example/gifs/Initial.gif "react-native-calendar-strip demo")
88

@@ -120,6 +120,11 @@ This is the list of all the props you can pass to the component so that you can
120120

121121
###### Top level style
122122
* style: PropTypes.any - Style for the top level CalendarStrip component
123+
* innerStyle: PropTypes.any - Style for the responsively sized inner view. This is necessary to account for padding/margin from the top level view. The inner view has style `flex:1` by default. If this component is nested within another dynamically sized container, remove the flex style by passing in `[]`.
124+
125+
###### Responsive sizing
126+
* maxDayComponentSize: PropTypes.number - (default 80) Maximum size that CalendarDay will responsively size up to.
127+
* minDayComponentSize: PropTypes.number - (default 10) Minimum size that CalendarDay will responsively size down to.
123128

124129
###### Icon
125130
* iconLeft: PropTypes.any - Icon to be used for the left icon. It accepts require statement with url to the image (`require('./img/icon.png')`), or object with remote uri `{uri: 'http://example.com/image.png'}`

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-calendar-strip",
3-
"version": "1.1.0",
3+
"version": "1.2.0",
44
"description": "Easy to use and visually stunning calendar component for React Native",
55
"main": "index.js",
66
"directories": {

src/Calendar.style.js

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,46 +21,37 @@ export default StyleSheet.create({
2121
alignItems: "center"
2222
},
2323
calendarHeader: {
24-
fontSize: 16,
2524
textAlign: "center",
2625
fontWeight: "bold",
2726
alignSelf: "center"
2827
},
2928
iconContainer: {
3029
justifyContent: "center",
31-
alignItems: "center"
30+
alignItems: "center",
31+
alignSelf: "center"
3232
},
3333
icon: {
34-
width: 20,
35-
height: 20,
3634
resizeMode: "contain"
3735
},
3836

3937
//CALENDAR DAY
4038
dateContainer: {
4139
justifyContent: "center",
4240
alignItems: "center",
43-
padding: 10,
44-
width: 50,
45-
height: 50,
46-
borderRadius: 50 / 2
41+
alignSelf: "center"
4742
},
4843
dateName: {
49-
fontSize: 10,
5044
textAlign: "center"
5145
},
5246
weekendDateName: {
53-
fontSize: 10,
5447
color: "#A7A7A7",
5548
textAlign: "center"
5649
},
5750
dateNumber: {
58-
fontSize: 18,
5951
fontWeight: "bold",
6052
textAlign: "center"
6153
},
6254
weekendDateNumber: {
63-
fontSize: 18,
6455
color: "#A7A7A7",
6556
fontWeight: "bold",
6657
textAlign: "center"

src/CalendarDay.js

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,17 @@ export default class CalendarDay extends Component {
6464
super(props);
6565

6666
this.state = {
67-
selected: props.selected
67+
selected: props.selected,
68+
containerSize: Math.round(props.size),
69+
containerPadding: Math.round(props.size / 5),
70+
containerBorderRadius: Math.round(props.size / 2),
71+
dateNameFontSize: Math.round(props.size / 2.8),
72+
dateNumberFontSize: Math.round(props.size / 5)
6873
};
6974
}
7075

7176
componentWillReceiveProps(nextProps) {
77+
newState = {};
7278
if (this.state.selected !== nextProps.selected) {
7379
if (this.props.daySelectionAnimation.type !== "") {
7480
let configurableAnimation = {
@@ -98,9 +104,18 @@ export default class CalendarDay extends Component {
98104
};
99105
LayoutAnimation.configureNext(configurableAnimation);
100106
}
107+
newState.selected = nextProps.selected;
108+
}
101109

102-
this.setState({ selected: nextProps.selected });
110+
if (nextProps.size !== this.props.size) {
111+
newState.containerSize = Math.round(nextProps.size);
112+
newState.containerPadding = Math.round(nextProps.size / 5);
113+
newState.containerBorderRadius = Math.round(nextProps.size / 2);
114+
newState.dateNameFontSize = Math.round(nextProps.size / 5);
115+
newState.dateNumberFontSize = Math.round(nextProps.size / 2.9);
103116
}
117+
118+
this.setState(newState);
104119
}
105120

106121
render() {
@@ -170,20 +185,38 @@ export default class CalendarDay extends Component {
170185
}
171186
}
172187

188+
let responsiveDateContainerStyle = {
189+
width: this.state.containerSize,
190+
height: this.state.containerSize,
191+
borderRadius: this.state.containerBorderRadius,
192+
padding: this.state.containerPadding
193+
};
194+
173195
return (
174196
<TouchableOpacity
175197
onPress={this.props.onDateSelected.bind(this, this.props.date)}
176198
>
177199
<View
178200
key={this.props.date}
179-
style={[styles.dateContainer, dateViewStyle]}
201+
style={[
202+
styles.dateContainer,
203+
responsiveDateContainerStyle,
204+
dateViewStyle
205+
]}
180206
>
181207
{this.props.showDayName &&
182-
<Text style={dateNameStyle}>
208+
<Text
209+
style={[dateNameStyle, { fontSize: this.state.dateNameFontSize }]}
210+
>
183211
{this.props.date.format("ddd").toUpperCase()}
184212
</Text>}
185213
{this.props.showDayNumber &&
186-
<Text style={dateNumberStyle}>
214+
<Text
215+
style={[
216+
dateNumberStyle,
217+
{ fontSize: this.state.dateNumberFontSize }
218+
]}
219+
>
187220
{this.props.date.date()}
188221
</Text>}
189222
</View>

src/CalendarHeader.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,13 @@ class CalendarHeader extends Component {
6363
this.props.calendarHeaderFormat
6464
);
6565
return (
66-
<Text style={[styles.calendarHeader, this.props.calendarHeaderStyle]}>
66+
<Text
67+
style={[
68+
styles.calendarHeader,
69+
{ fontSize: this.props.fontSize },
70+
this.props.calendarHeaderStyle
71+
]}
72+
>
6773
{headerText}
6874
</Text>
6975
);

src/CalendarStrip.js

Lines changed: 96 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import PropTypes from "prop-types";
1919
export default class CalendarStrip extends Component {
2020
static propTypes = {
2121
style: PropTypes.any,
22+
innerStyle: PropTypes.any,
2223
calendarColor: PropTypes.string,
2324

2425
startingDate: PropTypes.any,
@@ -45,6 +46,9 @@ export default class CalendarStrip extends Component {
4546
iconRightStyle: PropTypes.any,
4647
iconContainer: PropTypes.any,
4748

49+
maxDayComponentSize: PropTypes.number,
50+
minDayComponentSize: PropTypes.number,
51+
4852
calendarHeaderStyle: PropTypes.any,
4953
calendarHeaderFormat: PropTypes.string,
5054

@@ -77,7 +81,10 @@ export default class CalendarStrip extends Component {
7781
datesWhitelist: undefined,
7882
datesBlacklist: undefined,
7983
disabledDateOpacity: 0.3,
80-
customDatesStyles: []
84+
customDatesStyles: [],
85+
innerStyle: { flex: 1 },
86+
maxDayComponentSize: 80,
87+
minDayComponentSize: 10
8188
};
8289

8390
constructor(props) {
@@ -101,7 +108,11 @@ export default class CalendarStrip extends Component {
101108
this.state = {
102109
startingDate,
103110
selectedDate,
104-
...weekData
111+
...weekData,
112+
dayComponentWidth: 0,
113+
height: 0,
114+
monthFontSize: 0,
115+
selectorSize: 0
105116
};
106117

107118
this.resetAnimation();
@@ -441,6 +452,45 @@ export default class CalendarStrip extends Component {
441452
}
442453
}
443454

455+
// Responsive sizing based on container width.
456+
onLayout(event) {
457+
let csWidth = event.nativeEvent.layout.width;
458+
let numElements = this.numDaysInWeek;
459+
if (
460+
Array.isArray(this.props.leftSelector) &&
461+
this.props.leftSelector.length > 0
462+
) {
463+
numElements++;
464+
}
465+
if (
466+
Array.isArray(this.props.rightSelector) &&
467+
this.props.rightSelector.length > 0
468+
) {
469+
numElements++;
470+
}
471+
472+
let dayComponentWidth = csWidth / numElements;
473+
dayComponentWidth = Math.min(
474+
dayComponentWidth,
475+
this.props.maxDayComponentSize
476+
);
477+
dayComponentWidth = Math.max(
478+
dayComponentWidth,
479+
this.props.minDayComponentSize
480+
);
481+
let monthFontSize = Math.round(dayComponentWidth / 3.2);
482+
let selectorSize = Math.round(dayComponentWidth / 2.5);
483+
let height = this.props.showMonth ? monthFontSize : 0;
484+
height += this.props.showDate ? dayComponentWidth : 0; // assume square element sizes
485+
486+
this.setState({
487+
dayComponentWidth,
488+
height,
489+
monthFontSize,
490+
selectorSize
491+
});
492+
}
493+
444494
render() {
445495
let datesForWeek = this.state.datesForWeek;
446496
let datesRender = [];
@@ -467,6 +517,7 @@ export default class CalendarStrip extends Component {
467517
styleWeekend={this.props.styleWeekend}
468518
daySelectionAnimation={this.props.daySelectionAnimation}
469519
customStyle={this.state.datesCustomStylesForWeek[i]}
520+
size={this.state.dayComponentWidth}
470521
/>
471522
);
472523
datesRender.push(
@@ -489,6 +540,7 @@ export default class CalendarStrip extends Component {
489540
calendarHeaderFormat={this.props.calendarHeaderFormat}
490541
calendarHeaderStyle={this.props.calendarHeaderStyle}
491542
datesForWeek={this.state.datesForWeek}
543+
fontSize={this.state.monthFontSize}
492544
/>;
493545

494546
// calendarHeader renders above the dates & left/right selectors if dates are shown.
@@ -501,41 +553,48 @@ export default class CalendarStrip extends Component {
501553
this.props.style
502554
]}
503555
>
504-
{this.props.showDate && calendarHeader}
505-
<View style={styles.datesStrip}>
506-
<WeekSelector
507-
controlDate={this.props.minDate}
508-
iconComponent={this.props.leftSelector}
509-
iconContainerStyle={this.props.iconContainer}
510-
iconInstanceStyle={this.props.iconLeftStyle}
511-
iconStyle={this.props.iconStyle}
512-
imageSource={this.props.iconLeft}
513-
onPress={this.getPreviousWeek}
514-
weekEndDate={
515-
this.state.datesForWeek[this.state.datesForWeek.length - 1]
516-
}
517-
weekStartDate={this.state.datesForWeek[0]}
518-
/>
519-
520-
{this.props.showDate
521-
? <View style={styles.calendarDates}>
522-
{datesRender}
523-
</View>
524-
: calendarHeader}
525-
526-
<WeekSelector
527-
controlDate={this.props.maxDate}
528-
iconComponent={this.props.rightSelector}
529-
iconContainerStyle={this.props.iconContainer}
530-
iconInstanceStyle={this.props.iconRightStyle}
531-
iconStyle={this.props.iconStyle}
532-
imageSource={this.props.iconRight}
533-
onPress={this.getNextWeek}
534-
weekEndDate={
535-
this.state.datesForWeek[this.state.datesForWeek.length - 1]
536-
}
537-
weekStartDate={this.state.datesForWeek[0]}
538-
/>
556+
<View
557+
style={[this.props.innerStyle, { height: this.state.height }]}
558+
onLayout={this.onLayout.bind(this)}
559+
>
560+
{this.props.showDate && calendarHeader}
561+
<View style={styles.datesStrip}>
562+
<WeekSelector
563+
controlDate={this.props.minDate}
564+
iconComponent={this.props.leftSelector}
565+
iconContainerStyle={this.props.iconContainer}
566+
iconInstanceStyle={this.props.iconLeftStyle}
567+
iconStyle={this.props.iconStyle}
568+
imageSource={this.props.iconLeft}
569+
onPress={this.getPreviousWeek}
570+
weekEndDate={
571+
this.state.datesForWeek[this.state.datesForWeek.length - 1]
572+
}
573+
weekStartDate={this.state.datesForWeek[0]}
574+
size={this.state.selectorSize}
575+
/>
576+
577+
{this.props.showDate
578+
? <View style={styles.calendarDates}>
579+
{datesRender}
580+
</View>
581+
: calendarHeader}
582+
583+
<WeekSelector
584+
controlDate={this.props.maxDate}
585+
iconComponent={this.props.rightSelector}
586+
iconContainerStyle={this.props.iconContainer}
587+
iconInstanceStyle={this.props.iconRightStyle}
588+
iconStyle={this.props.iconStyle}
589+
imageSource={this.props.iconRight}
590+
onPress={this.getNextWeek}
591+
weekEndDate={
592+
this.state.datesForWeek[this.state.datesForWeek.length - 1]
593+
}
594+
weekStartDate={this.state.datesForWeek[0]}
595+
size={this.state.selectorSize}
596+
/>
597+
</View>
539598
</View>
540599
</View>
541600
);

0 commit comments

Comments
 (0)