Skip to content

Commit

Permalink
Responsively size calendar strip to container width.
Browse files Browse the repository at this point in the history
See #14
  • Loading branch information
peacechen committed Jul 21, 2017
1 parent 5799315 commit 810b15b
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 57 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

`<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!
`<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.

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

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

###### Top level style
* style: PropTypes.any - Style for the top level CalendarStrip component
* 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 `[]`.

###### Responsive sizing
* maxDayComponentSize: PropTypes.number - (default 80) Maximum size that CalendarDay will responsively size up to.
* minDayComponentSize: PropTypes.number - (default 10) Minimum size that CalendarDay will responsively size down to.

###### Icon
* 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'}`
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-calendar-strip",
"version": "1.1.0",
"version": "1.2.0",
"description": "Easy to use and visually stunning calendar component for React Native",
"main": "index.js",
"directories": {
Expand Down
15 changes: 3 additions & 12 deletions src/Calendar.style.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,46 +21,37 @@ export default StyleSheet.create({
alignItems: "center"
},
calendarHeader: {
fontSize: 16,
textAlign: "center",
fontWeight: "bold",
alignSelf: "center"
},
iconContainer: {
justifyContent: "center",
alignItems: "center"
alignItems: "center",
alignSelf: "center"
},
icon: {
width: 20,
height: 20,
resizeMode: "contain"
},

//CALENDAR DAY
dateContainer: {
justifyContent: "center",
alignItems: "center",
padding: 10,
width: 50,
height: 50,
borderRadius: 50 / 2
alignSelf: "center"
},
dateName: {
fontSize: 10,
textAlign: "center"
},
weekendDateName: {
fontSize: 10,
color: "#A7A7A7",
textAlign: "center"
},
dateNumber: {
fontSize: 18,
fontWeight: "bold",
textAlign: "center"
},
weekendDateNumber: {
fontSize: 18,
color: "#A7A7A7",
fontWeight: "bold",
textAlign: "center"
Expand Down
43 changes: 38 additions & 5 deletions src/CalendarDay.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,17 @@ export default class CalendarDay extends Component {
super(props);

this.state = {
selected: props.selected
selected: props.selected,
containerSize: Math.round(props.size),
containerPadding: Math.round(props.size / 5),
containerBorderRadius: Math.round(props.size / 2),
dateNameFontSize: Math.round(props.size / 2.8),
dateNumberFontSize: Math.round(props.size / 5)
};
}

componentWillReceiveProps(nextProps) {
newState = {};
if (this.state.selected !== nextProps.selected) {
if (this.props.daySelectionAnimation.type !== "") {
let configurableAnimation = {
Expand Down Expand Up @@ -98,9 +104,18 @@ export default class CalendarDay extends Component {
};
LayoutAnimation.configureNext(configurableAnimation);
}
newState.selected = nextProps.selected;
}

this.setState({ selected: nextProps.selected });
if (nextProps.size !== this.props.size) {
newState.containerSize = Math.round(nextProps.size);
newState.containerPadding = Math.round(nextProps.size / 5);
newState.containerBorderRadius = Math.round(nextProps.size / 2);
newState.dateNameFontSize = Math.round(nextProps.size / 5);
newState.dateNumberFontSize = Math.round(nextProps.size / 2.9);
}

this.setState(newState);
}

render() {
Expand Down Expand Up @@ -170,20 +185,38 @@ export default class CalendarDay extends Component {
}
}

let responsiveDateContainerStyle = {
width: this.state.containerSize,
height: this.state.containerSize,
borderRadius: this.state.containerBorderRadius,
padding: this.state.containerPadding
};

return (
<TouchableOpacity
onPress={this.props.onDateSelected.bind(this, this.props.date)}
>
<View
key={this.props.date}
style={[styles.dateContainer, dateViewStyle]}
style={[
styles.dateContainer,
responsiveDateContainerStyle,
dateViewStyle
]}
>
{this.props.showDayName &&
<Text style={dateNameStyle}>
<Text
style={[dateNameStyle, { fontSize: this.state.dateNameFontSize }]}
>
{this.props.date.format("ddd").toUpperCase()}
</Text>}
{this.props.showDayNumber &&
<Text style={dateNumberStyle}>
<Text
style={[
dateNumberStyle,
{ fontSize: this.state.dateNumberFontSize }
]}
>
{this.props.date.date()}
</Text>}
</View>
Expand Down
8 changes: 7 additions & 1 deletion src/CalendarHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,13 @@ class CalendarHeader extends Component {
this.props.calendarHeaderFormat
);
return (
<Text style={[styles.calendarHeader, this.props.calendarHeaderStyle]}>
<Text
style={[
styles.calendarHeader,
{ fontSize: this.props.fontSize },
this.props.calendarHeaderStyle
]}
>
{headerText}
</Text>
);
Expand Down
133 changes: 96 additions & 37 deletions src/CalendarStrip.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import PropTypes from "prop-types";
export default class CalendarStrip extends Component {
static propTypes = {
style: PropTypes.any,
innerStyle: PropTypes.any,
calendarColor: PropTypes.string,

startingDate: PropTypes.any,
Expand All @@ -45,6 +46,9 @@ export default class CalendarStrip extends Component {
iconRightStyle: PropTypes.any,
iconContainer: PropTypes.any,

maxDayComponentSize: PropTypes.number,
minDayComponentSize: PropTypes.number,

calendarHeaderStyle: PropTypes.any,
calendarHeaderFormat: PropTypes.string,

Expand Down Expand Up @@ -77,7 +81,10 @@ export default class CalendarStrip extends Component {
datesWhitelist: undefined,
datesBlacklist: undefined,
disabledDateOpacity: 0.3,
customDatesStyles: []
customDatesStyles: [],
innerStyle: { flex: 1 },
maxDayComponentSize: 80,
minDayComponentSize: 10
};

constructor(props) {
Expand All @@ -101,7 +108,11 @@ export default class CalendarStrip extends Component {
this.state = {
startingDate,
selectedDate,
...weekData
...weekData,
dayComponentWidth: 0,
height: 0,
monthFontSize: 0,
selectorSize: 0
};

this.resetAnimation();
Expand Down Expand Up @@ -441,6 +452,45 @@ export default class CalendarStrip extends Component {
}
}

// Responsive sizing based on container width.
onLayout(event) {
let csWidth = event.nativeEvent.layout.width;
let numElements = this.numDaysInWeek;
if (
Array.isArray(this.props.leftSelector) &&
this.props.leftSelector.length > 0
) {
numElements++;
}
if (
Array.isArray(this.props.rightSelector) &&
this.props.rightSelector.length > 0
) {
numElements++;
}

let dayComponentWidth = csWidth / numElements;
dayComponentWidth = Math.min(
dayComponentWidth,
this.props.maxDayComponentSize
);
dayComponentWidth = Math.max(
dayComponentWidth,
this.props.minDayComponentSize
);
let monthFontSize = Math.round(dayComponentWidth / 3.2);
let selectorSize = Math.round(dayComponentWidth / 2.5);
let height = this.props.showMonth ? monthFontSize : 0;
height += this.props.showDate ? dayComponentWidth : 0; // assume square element sizes

this.setState({
dayComponentWidth,
height,
monthFontSize,
selectorSize
});
}

render() {
let datesForWeek = this.state.datesForWeek;
let datesRender = [];
Expand All @@ -467,6 +517,7 @@ export default class CalendarStrip extends Component {
styleWeekend={this.props.styleWeekend}
daySelectionAnimation={this.props.daySelectionAnimation}
customStyle={this.state.datesCustomStylesForWeek[i]}
size={this.state.dayComponentWidth}
/>
);
datesRender.push(
Expand All @@ -489,6 +540,7 @@ export default class CalendarStrip extends Component {
calendarHeaderFormat={this.props.calendarHeaderFormat}
calendarHeaderStyle={this.props.calendarHeaderStyle}
datesForWeek={this.state.datesForWeek}
fontSize={this.state.monthFontSize}
/>;

// calendarHeader renders above the dates & left/right selectors if dates are shown.
Expand All @@ -501,41 +553,48 @@ export default class CalendarStrip extends Component {
this.props.style
]}
>
{this.props.showDate && calendarHeader}
<View style={styles.datesStrip}>
<WeekSelector
controlDate={this.props.minDate}
iconComponent={this.props.leftSelector}
iconContainerStyle={this.props.iconContainer}
iconInstanceStyle={this.props.iconLeftStyle}
iconStyle={this.props.iconStyle}
imageSource={this.props.iconLeft}
onPress={this.getPreviousWeek}
weekEndDate={
this.state.datesForWeek[this.state.datesForWeek.length - 1]
}
weekStartDate={this.state.datesForWeek[0]}
/>

{this.props.showDate
? <View style={styles.calendarDates}>
{datesRender}
</View>
: calendarHeader}

<WeekSelector
controlDate={this.props.maxDate}
iconComponent={this.props.rightSelector}
iconContainerStyle={this.props.iconContainer}
iconInstanceStyle={this.props.iconRightStyle}
iconStyle={this.props.iconStyle}
imageSource={this.props.iconRight}
onPress={this.getNextWeek}
weekEndDate={
this.state.datesForWeek[this.state.datesForWeek.length - 1]
}
weekStartDate={this.state.datesForWeek[0]}
/>
<View
style={[this.props.innerStyle, { height: this.state.height }]}
onLayout={this.onLayout.bind(this)}
>
{this.props.showDate && calendarHeader}
<View style={styles.datesStrip}>
<WeekSelector
controlDate={this.props.minDate}
iconComponent={this.props.leftSelector}
iconContainerStyle={this.props.iconContainer}
iconInstanceStyle={this.props.iconLeftStyle}
iconStyle={this.props.iconStyle}
imageSource={this.props.iconLeft}
onPress={this.getPreviousWeek}
weekEndDate={
this.state.datesForWeek[this.state.datesForWeek.length - 1]
}
weekStartDate={this.state.datesForWeek[0]}
size={this.state.selectorSize}
/>

{this.props.showDate
? <View style={styles.calendarDates}>
{datesRender}
</View>
: calendarHeader}

<WeekSelector
controlDate={this.props.maxDate}
iconComponent={this.props.rightSelector}
iconContainerStyle={this.props.iconContainer}
iconInstanceStyle={this.props.iconRightStyle}
iconStyle={this.props.iconStyle}
imageSource={this.props.iconRight}
onPress={this.getNextWeek}
weekEndDate={
this.state.datesForWeek[this.state.datesForWeek.length - 1]
}
weekStartDate={this.state.datesForWeek[0]}
size={this.state.selectorSize}
/>
</View>
</View>
</View>
);
Expand Down

0 comments on commit 810b15b

Please sign in to comment.