diff --git a/Calendar.js b/Calendar.js
index 8eff679..0a3ad31 100644
--- a/Calendar.js
+++ b/Calendar.js
@@ -8,6 +8,7 @@ import {
Text,
Modal,
Image,
+ Alert,
StyleSheet,
ScrollView,
Dimensions,
@@ -15,62 +16,40 @@ import {
} from 'react-native';
import Moment from 'moment';
import styles from './CalendarStyle';
+import { customStylesProvider } from './CustomStylesProvider';
import MonthList from './MonthList';
const ICON = {
close: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAADGklEQVR4Xu3b3XXTMBTAcV1Leu8I3YAyAWECygSlE9BOQJmAdAK6QWGCphNQNmAE+mzZl6Mc5xzXtiLJ1r0STfLqJM3/Z9muPwTiwF9w4P3iCHAcAQ4BRDxt2/aDEOKkqqqfAPD0P2EZYy6EEJ/sbwaATVVVtwDwd9gwuQkYY+wHv9n43QcQca21vi4dARFPmqa5F0Ks+r8VEZ+UUu+HCCMAu+abpvnVj+990Z1S6rJUBBtvjHkAgLOp34iIX7XWN/1lI4Cmaa4Q0a5916tIBF+8jUHER631i5ExAqjr+gYAvnjWclEIIfHBAIh41m0CvpFeBEJofBdzqZS627sJ2IV1Xa8B4LNPQAiRFSEmfmr4b48QrkhjjJWyhxLfKwtCZPxvpdQq+DC4Ky4VIVX83hFQKkLK+CAA+6ZSRkLq+GCAEhAo4qMAciJQxUcD5ECgjJ8FwIlAHT8bgAOBI34RACUCV/xiAAoEzvgkACkRuOOTAaRAyBGfFGAJQq745ABzEHLGkwDEItgLMK5reP3zcER0ntL6ztf3LSe7MRJxAuX9/VTxZCNgxqm0E4EynhwgcnMYIVDHswDMReCIZwOIReCKZwOIOdR12wHbhVayo8Bug54Rv/soCwIpwIJ4NgQygATxLAgkAAnjyRGSA8TE27199+BFtjtQSQFi43e3qyL+bU6+Y0wGMDd+xr/NSRGSACyNz4mwGCBVfC6ERQCp43MgzAagiudGmAVAHc+JEA3AFc+FEAXAHc+BEAyQK54aIQggdzwlgheglHgqhL0ApcVTIDgBSo1PjTAJUHp8SgTXfIGH4fP2U3cuOK/euu6chJ5KI+Kt1vpq+D0jgG6yxHfnrZpuQQnxsSNBSvl2OPNl6nH5DQC82wdQUnwMAgBcSynX/bZogBLjIxA+KqV++ACcEyZKjg9AeJZSnobMGbLzbuxm8KYvZZ+3V0qdTz1y7ttfcC+fmO/wjIjnWuuNdydo39AdBu0eczu/BgDsdbgXMy24o2L/nn3wom3bFSL+kVLaFTqaMrdti/3i1/b+I8BrW6OxPQc/Av4BDSZYbnPWwJkAAAAASUVORK5CYII='
};
export default class Calendar extends Component {
static propTypes = {
- i18n: PropTypes.string,
format: PropTypes.string,
customI18n: PropTypes.object,
+ customStyles: PropTypes.object,
+ dateRangeValidator: PropTypes.object,
color: PropTypes.object,
minDate: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
maxDate: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)])
}
static defaultProps = {
format: 'YYYY-MM-DD',
- i18n: 'en',
customI18n: {},
+ customStyles: {},
+ dateRangeValidator: null,
color: {}
}
- static I18N_MAP = {
- 'zh': {
- 'w': ['', '一', '二', '三', '四', '五', '六', '日'],
- 'weekday': ['', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'],
- 'text': {
- 'start': '开 始',
- 'end': '结 束',
- 'date': '日 期',
- 'save': '保 存',
- 'clear': '清除'
- },
- 'date': 'M月D日'
+ static DEFAULT_I18N_MAP = {
+ 'firstWeekday': 7,
+ 'w': ['Mon', 'Tues', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun'],
+ 'weekday': ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
+ 'text': {
+ 'start': 'Start',
+ 'end': 'End',
+ 'date': 'Date',
+ 'save': 'Save',
+ 'clear': 'Reset'
},
- 'en': {
- 'w': ['', 'Mon', 'Tues', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun'],
- 'weekday': ['', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
- 'text': {
- 'start': 'Start',
- 'end': 'End',
- 'date': 'Date',
- 'save': 'Save',
- 'clear': 'Reset'
- },
- 'date': 'DD / MM'
- },
- 'jp': {
- 'w': ['', '月', '火', '水', '木', '金', '土', '日'],
- 'weekday': ['', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日', '日曜日'],
- 'text': {
- 'start': 'スタート',
- 'end': 'エンド',
- 'date': '時 間',
- 'save': '確 認',
- 'clear': 'クリア'
- },
- 'date': 'M月D日'
- }
+ 'date': 'DD / MM'
}
constructor (props) {
super(props);
@@ -83,6 +62,7 @@ export default class Calendar extends Component {
this._getDateRange = this._getDateRange.bind(this);
this._onChoose = this._onChoose.bind(this);
this._resetCalendar = this._resetCalendar.bind(this);
+ this._getFirstWeekday = this._getFirstWeekday.bind(this);
this.close = this.close.bind(this);
this.cancel = this.cancel.bind(this);
this.open = this.open.bind(this);
@@ -95,14 +75,13 @@ export default class Calendar extends Component {
}
_i18n (data, type) {
const {
- i18n,
customI18n
} = this.props;
if (~['w', 'weekday', 'text'].indexOf(type)) {
- return (customI18n[type] || {})[data] || Calendar.I18N_MAP[i18n][type][data];
+ return (customI18n[type] || {})[data] || Calendar.DEFAULT_I18N_MAP[type][data];
}
if (type === 'date') {
- return data.format(customI18n[type] || Calendar.I18N_MAP[i18n][type]);
+ return data.format(customI18n[type] || Calendar.DEFAULT_I18N_MAP[type]);
}
}
_resetCalendar () {
@@ -118,12 +97,15 @@ export default class Calendar extends Component {
this.setState({
startDate: isStartValid ? start : null,
startDateText: isStartValid ? this._i18n(start, 'date') : '',
- startWeekdayText: isStartValid ? this._i18n(start.isoWeekday(), 'weekday') : '',
+ startWeekdayText: isStartValid ? this._i18n(this._getIsoWeekdayForI18n(start), 'weekday') : '',
endDate: isEndValid ? end: null,
endDateText: isEndValid ? this._i18n(end, 'date') : '',
- endWeekdayText: isEndValid ? this._i18n(end.isoWeekday(), 'weekday') : ''
+ endWeekdayText: isEndValid ? this._i18n(this._getIsoWeekdayForI18n(end), 'weekday') : ''
});
}
+ _getIsoWeekdayForI18n (day) {
+ return day.isoWeekday() - 1;
+ }
_getDateRange () {
const {
maxDate,
@@ -158,7 +140,7 @@ export default class Calendar extends Component {
startDate: day,
endDate: null,
startDateText: this._i18n(day, 'date'),
- startWeekdayText: this._i18n(day.isoWeekday(), 'weekday'),
+ startWeekdayText: this._i18n(this._getIsoWeekdayForI18n(day), 'weekday'),
endDateText: '',
endWeekdayText: '',
});
@@ -166,10 +148,30 @@ export default class Calendar extends Component {
this.setState({
endDate: day,
endDateText: this._i18n(day, 'date'),
- endWeekdayText: this._i18n(day.isoWeekday(), 'weekday')
+ endWeekdayText: this._i18n(this._getIsoWeekdayForI18n(day), 'weekday')
});
}
}
+ _getFirstWeekday () {
+ let defaultFirstWeekday = Calendar.DEFAULT_I18N_MAP['firstWeekday'];
+ let firstWeekday = this.props.customI18n['firstWeekday'] || defaultFirstWeekday;
+ return ((firstWeekday <= 7) ? firstWeekday : defaultFirstWeekday);
+ }
+ _getWeeknums () {
+ let firstWeekday = this._getFirstWeekday();
+ if (firstWeekday > 7) {
+ firstWeekday = Calendar.DEFAULT_I18N_MAP['firstWeekday'];;
+ }
+ let days = [];
+ for (let i = 0; i < 7; i++) {
+ days.push(firstWeekday - 1);
+ firstWeekday++;
+ if (firstWeekday > 7) {
+ firstWeekday = 1;
+ }
+ }
+ return days;
+ }
cancel () {
this.close();
this._resetCalendar();
@@ -201,6 +203,16 @@ export default class Calendar extends Component {
} = this.state;
let startMoment = startDate ? startDate.clone() : null;
let endMoment = endDate ? endDate.clone() : null;
+ if (startMoment != null && endMoment != null && this.props.dateRangeValidator != null) {
+ const daysBetween = endMoment.diff(startMoment, 'days');
+ if (daysBetween < (this.props.dateRangeValidator.minDaysBetween || 1)
+ || daysBetween > (this.props.dateRangeValidator.maxDaysBetween || 30)) {
+ Alert.alert(
+ this.props.dateRangeValidator.msg || 'Invalid range'
+ );
+ return false;
+ }
+ }
this.props.onConfirm && this.props.onConfirm({
startDate: startMoment ? startMoment.toDate() : null,
endDate: endMoment ? endMoment.toDate() : null,
@@ -223,6 +235,10 @@ export default class Calendar extends Component {
subColor = '#fff',
borderColor = 'rgba(255, 255, 255, 0.50)'
} = this.props.color;
+ const {
+ customI18n,
+ customStyles
+ } = this.props;
let color = {mainColor, subColor, borderColor};
let mainBack = {backgroundColor: mainColor};
let subBack = {backgroundColor: subColor};
@@ -250,64 +266,66 @@ export default class Calendar extends Component {
underlayColor="transparent"
activeOpacity={0.8}
onPress={this.clear}>
- {this._i18n('clear', 'text')}
+ {this._i18n('clear', 'text')}
}
-
+
{startDateText || this._i18n('start', 'text')}
-
+
{startWeekdayText || this._i18n('date', 'text')}
-
+
{endDateText || this._i18n('end', 'text')}
-
+
{endWeekdayText || this._i18n('date', 'text')}
- {[7, 1, 2, 3, 4, 5, 6].map(item =>
- {this._i18n(item, 'w')}
+ {this._getWeeknums().map(item =>
+ {this._i18n(item, 'w')}
)}
-
+
{isValid ?
+ style={[styles.confirmText, subFontColor, customStylesProvider(customStyles, 'confirmBtnText')]}>
{this._i18n('save', 'text')}
:
-
+
+ style={[styles.confirmText, styles.confirmTextDisabled, customStylesProvider(customStyles, 'confirmBtnText')]}>
{this._i18n('save', 'text')}
diff --git a/CustomStylesProvider.js b/CustomStylesProvider.js
new file mode 100644
index 0000000..527ff83
--- /dev/null
+++ b/CustomStylesProvider.js
@@ -0,0 +1,4 @@
+
+export const customStylesProvider = function (styles, key) {
+ return styles[key] || {};
+};
diff --git a/Day/index.js b/Day/index.js
index 74579df..1e7619d 100644
--- a/Day/index.js
+++ b/Day/index.js
@@ -11,10 +11,15 @@ import {
} from 'react-native';
import Moment from 'moment';
import styles from './style';
+import { customStylesProvider } from '../CustomStylesProvider';
export default class Day extends Component {
static propTypes = {
- onChoose: PropTypes.func
+ onChoose: PropTypes.func,
+ customStyles: PropTypes.object
+ }
+ static defaultProps = {
+ customStyles: {}
}
constructor (props) {
super(props);
@@ -56,7 +61,8 @@ export default class Day extends Component {
render () {
const {
date,
- color
+ color,
+ customStyles
} = this.props;
let text = date ? date.date() : '';
let mainColor = {color: color.mainColor};
@@ -77,10 +83,10 @@ export default class Day extends Component {
style={[styles.day, this.isToday && styles.today, this.isFocus && subBack]}
underlayColor="rgba(255, 255, 255, 0.35)"
onPress={this._chooseDay}>
- {text}
+ {text}
:
- {text}
+ {text}
}
diff --git a/Month/index.js b/Month/index.js
index 141fc6f..eade7b4 100644
--- a/Month/index.js
+++ b/Month/index.js
@@ -12,54 +12,62 @@ import {
import Moment from 'moment';
import styles from './style';
import Day from '../Day';
+import { customStylesProvider } from '../CustomStylesProvider';
export default class Month extends Component {
+ static propTypes = {
+ firstWeekday: PropTypes.number,
+ customStyles: PropTypes.object
+ }
+ static defaultProps = {
+ firstWeekday: 7,
+ customStyles: {}
+ }
constructor (props) {
super(props);
this._getDayList = this._getDayList.bind(this);
this._renderDayRow = this._renderDayRow.bind(this);
this._getMonthText = this._getMonthText.bind(this);
}
- static I18N_MAP = {
- 'zh': [
- '一月', '二月', '三月', '四月', '五月', '六月',
- '七月', '八月', '九月', '十月', '十一月', '十二月'
- ],
- 'jp': [
- '一月', '二月', '三月', '四月', '五月', '六月',
- '七月', '八月', '九月', '十月', '十一月', '十二月'
- ],
- 'en': [
- 'January', 'February', 'March', 'April', 'May', 'June',
- 'July', 'August', 'September', 'October', 'November', 'December'
- ]
- }
+ static DEFAULT_I18N_MONTH_NAMES = [
+ 'January', 'February', 'March', 'April', 'May', 'June',
+ 'July', 'August', 'September', 'October', 'November', 'December'
+ ]
+
_getMonthText () {
const {
month,
today,
- i18n
+ customI18n
} = this.props;
let y = month.year();
let m = month.month();
let year = today.year();
+ let monthNames = Month.DEFAULT_I18N_MONTH_NAMES;
+ if (customI18n && customI18n['m']) {
+ monthNames = customI18n['m'];
+ }
if (year === y) {
- return Month.I18N_MAP[i18n][m];
+ return monthNames[m] || Month.DEFAULT_I18N_MONTH_NAMES[m];
} else {
- if (i18n === 'en') {
- return `${Month.I18N_MAP[i18n][m]}, ${y}`;
- }
- return month.format('YYYY年M月');
+ return `${monthNames[m] || Month.DEFAULT_I18N_MONTH_NAMES[m]}, ${y}`;
}
}
_getDayList (date) {
let dayList;
let month = date.month();
let weekday = date.isoWeekday();
- if (weekday === 7) {
+ let firstWeekday = this.props.firstWeekday;
+ if (weekday === firstWeekday) {
dayList = [];
} else {
- dayList = new Array(weekday).fill({
+ let arrayLength;
+ if (weekday > firstWeekday) {
+ arrayLength = Math.abs(weekday - firstWeekday);
+ } else {
+ arrayLength = 7 - Math.abs(weekday - firstWeekday);
+ }
+ dayList = new Array(arrayLength).fill({
empty: date.clone().subtract(1, 'h')
});
}
@@ -71,14 +79,23 @@ export default class Month extends Component {
}
date.subtract(1, 'days');
weekday = date.isoWeekday();
- if (weekday === 7) {
- return dayList.concat(new Array(6).fill({
+ let endList;
+ if (weekday === firstWeekday) {
+ endList = new Array(6).fill({
+ empty: date.clone().hour(1)
+ });
+ } else {
+ let arrayLength;
+ if (weekday > firstWeekday) {
+ arrayLength = Math.abs((weekday - firstWeekday) - 6);
+ } else {
+ arrayLength = Math.abs(weekday - firstWeekday) - 1;
+ }
+ endList = new Array(arrayLength).fill({
empty: date.clone().hour(1)
- }));
+ });
}
- return dayList.concat(new Array(Math.abs(weekday - 6)).fill({
- empty: date.clone().hour(1)
- }));
+ return dayList.concat(endList);
}
_renderDayRow (dayList, index) {
const {
@@ -102,7 +119,8 @@ export default class Month extends Component {
const {
month,
today,
- color
+ color,
+ customStyles
} = this.props;
let subColor = {color: color.subColor};
let titleText = this._getMonthText();
@@ -111,7 +129,7 @@ export default class Month extends Component {
return (
- {titleText}
+ {titleText}
{rowArray.map((item, i) =>
diff --git a/__tests__/Calendar.test.js b/__tests__/Calendar.test.js
index 0abc63f..3be9e02 100644
--- a/__tests__/Calendar.test.js
+++ b/__tests__/Calendar.test.js
@@ -26,7 +26,6 @@ let color = {
let cal = shallow(
{}}
color={color}
/>
@@ -151,7 +149,6 @@ test('It renders MonthList correctly', done => {
let month = shallow(
{text}
{this.calendar = calendar;}}
+ customI18n={customI18n}
+ customStyles={customStyles}
+ dateRangeValidator={dateRangeValidator}
format="YYYYMMDD"
minDate="20170510"
maxDate="20180412"