Skip to content

Commit f149c68

Browse files
authored
Merge pull request react-dates#371 from daltones/feat/first-weekday
Feature: add firstDayOfWeek prop
2 parents 19a10f7 + 139e274 commit f149c68

16 files changed

+225
-35
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ withFullScreenPortal: PropTypes.bool,
105105
daySize: nonNegativeInteger,
106106
isRTL: PropTypes.bool,
107107
initialVisibleMonth: PropTypes.func,
108+
firstDayOfWeek: PropTypes.oneOf([0, 1, 2, 3, 4, 5, 6]),
108109
numberOfMonths: PropTypes.number,
109110
keepOpenOnDateSelect: PropTypes.bool,
110111
reopenPickerOnClearDates: PropTypes.bool,
@@ -171,6 +172,7 @@ horizontalMargin: PropTypes.number,
171172
withPortal: PropTypes.bool,
172173
withFullScreenPortal: PropTypes.bool,
173174
initialVisibleMonth: PropTypes.func,
175+
firstDayOfWeek: PropTypes.oneOf([0, 1, 2, 3, 4, 5, 6]),
174176
numberOfMonths: PropTypes.number,
175177
keepOpenOnDateSelect: PropTypes.bool,
176178
reopenPickerOnClearDate: PropTypes.bool,

constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ module.exports = {
1515

1616
DAY_SIZE: 39,
1717
BLOCKED_MODIFIER: 'blocked',
18+
WEEKDAYS: [0, 1, 2, 3, 4, 5, 6],
1819
};

src/components/CalendarMonth.jsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import isSameDay from '../utils/isSameDay';
1818
import toISODateString from '../utils/toISODateString';
1919

2020
import ScrollableOrientationShape from '../shapes/ScrollableOrientationShape';
21+
import DayOfWeekShape from '../shapes/DayOfWeekShape';
2122

2223
import {
2324
HORIZONTAL_ORIENTATION,
@@ -38,6 +39,7 @@ const propTypes = forbidExtraProps({
3839
onDayMouseLeave: PropTypes.func,
3940
renderMonth: PropTypes.func,
4041
renderDay: PropTypes.func,
42+
firstDayOfWeek: DayOfWeekShape,
4143

4244
focusedDate: momentPropTypes.momentObj, // indicates focusable day
4345
isFocused: PropTypes.bool, // indicates whether or not to move focus to focusable day
@@ -59,6 +61,7 @@ const defaultProps = {
5961
onDayMouseLeave() {},
6062
renderMonth: null,
6163
renderDay: null,
64+
firstDayOfWeek: null,
6265

6366
focusedDate: null,
6467
isFocused: false,
@@ -71,16 +74,27 @@ const defaultProps = {
7174
export default class CalendarMonth extends React.Component {
7275
constructor(props) {
7376
super(props);
77+
7478
this.state = {
75-
weeks: getCalendarMonthWeeks(props.month, props.enableOutsideDays),
79+
weeks: getCalendarMonthWeeks(
80+
props.month,
81+
props.enableOutsideDays,
82+
props.firstDayOfWeek == null ? moment.localeData().firstDayOfWeek() : props.firstDayOfWeek,
83+
),
7684
};
7785
}
7886

7987
componentWillReceiveProps(nextProps) {
80-
const { month, enableOutsideDays } = nextProps;
81-
if (!month.isSame(this.props.month)) {
88+
const { month, enableOutsideDays, firstDayOfWeek } = nextProps;
89+
if (!month.isSame(this.props.month)
90+
|| enableOutsideDays !== this.props.enableOutsideDays
91+
|| firstDayOfWeek !== this.props.firstDayOfWeek) {
8292
this.setState({
83-
weeks: getCalendarMonthWeeks(month, enableOutsideDays),
93+
weeks: getCalendarMonthWeeks(
94+
month,
95+
enableOutsideDays,
96+
firstDayOfWeek == null ? moment.localeData().firstDayOfWeek() : firstDayOfWeek,
97+
),
8498
});
8599
}
86100
}

src/components/CalendarMonthGrid.jsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import toISOMonthString from '../utils/toISOMonthString';
1919
import isAfterDay from '../utils/isAfterDay';
2020

2121
import ScrollableOrientationShape from '../shapes/ScrollableOrientationShape';
22+
import DayOfWeekShape from '../shapes/DayOfWeekShape';
2223

2324
import {
2425
HORIZONTAL_ORIENTATION,
@@ -45,6 +46,7 @@ const propTypes = forbidExtraProps({
4546
daySize: nonNegativeInteger,
4647
focusedDate: momentPropTypes.momentObj, // indicates focusable day
4748
isFocused: PropTypes.bool, // indicates whether or not to move focus to focusable day
49+
firstDayOfWeek: DayOfWeekShape,
4850

4951
// i18n
5052
monthFormat: PropTypes.string,
@@ -69,6 +71,7 @@ const defaultProps = {
6971
daySize: DAY_SIZE,
7072
focusedDate: null,
7173
isFocused: false,
74+
firstDayOfWeek: null,
7275

7376
// i18n
7477
monthFormat: 'MMMM YYYY', // english locale
@@ -175,6 +178,7 @@ export default class CalendarMonthGrid extends React.Component {
175178
renderMonth,
176179
renderDay,
177180
onMonthTransitionEnd,
181+
firstDayOfWeek,
178182
focusedDate,
179183
isFocused,
180184
phrases,
@@ -228,6 +232,7 @@ export default class CalendarMonthGrid extends React.Component {
228232
onDayClick={onDayClick}
229233
renderMonth={renderMonth}
230234
renderDay={renderDay}
235+
firstDayOfWeek={firstDayOfWeek}
231236
daySize={daySize}
232237
focusedDate={isVisible ? focusedDate : null}
233238
isFocused={isFocused}

src/components/DateRangePicker.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ const defaultProps = {
7070
hideKeyboardShortcutsPanel: false,
7171
daySize: DAY_SIZE,
7272
isRTL: false,
73+
firstDayOfWeek: null,
7374

7475
// navigation related props
7576
navPrev: null,
@@ -305,6 +306,7 @@ export default class DateRangePicker extends React.Component {
305306
keepOpenOnDateSelect,
306307
renderDay,
307308
renderCalendarInfo,
309+
firstDayOfWeek,
308310
initialVisibleMonth,
309311
hideKeyboardShortcutsPanel,
310312
customCloseIcon,
@@ -362,6 +364,7 @@ export default class DateRangePicker extends React.Component {
362364
onBlur={this.onDayPickerBlur}
363365
phrases={phrases}
364366
isRTL={isRTL}
367+
firstDayOfWeek={firstDayOfWeek}
365368
/>
366369

367370
{withFullScreenPortal && (

src/components/DayPicker.jsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import getActiveElement from '../utils/getActiveElement';
2626
import isDayVisible from '../utils/isDayVisible';
2727

2828
import ScrollableOrientationShape from '../shapes/ScrollableOrientationShape';
29+
import DayOfWeekShape from '../shapes/DayOfWeekShape';
2930

3031
import {
3132
HORIZONTAL_ORIENTATION,
@@ -48,6 +49,7 @@ const propTypes = forbidExtraProps({
4849
onOutsideClick: PropTypes.func,
4950
hidden: PropTypes.bool,
5051
initialVisibleMonth: PropTypes.func,
52+
firstDayOfWeek: DayOfWeekShape,
5153
renderCalendarInfo: PropTypes.func,
5254
hideKeyboardShortcutsPanel: PropTypes.bool,
5355
daySize: nonNegativeInteger,
@@ -90,6 +92,7 @@ export const defaultProps = {
9092
onOutsideClick() {},
9193
hidden: false,
9294
initialVisibleMonth: () => moment(),
95+
firstDayOfWeek: null,
9396
renderCalendarInfo: null,
9497
hideKeyboardShortcutsPanel: false,
9598
daySize: DAY_SIZE,
@@ -682,11 +685,16 @@ export default class DayPicker extends React.Component {
682685
style = verticalStyle;
683686
}
684687

688+
let { firstDayOfWeek } = this.props;
689+
if (firstDayOfWeek == null) {
690+
firstDayOfWeek = moment.localeData().firstDayOfWeek();
691+
}
692+
685693
const header = [];
686694
for (let i = 0; i < 7; i += 1) {
687695
header.push(
688696
<li key={i} style={{ width: daySize }}>
689-
<small>{moment().weekday(i).format('dd')}</small>
697+
<small>{moment().day((i + firstDayOfWeek) % 7).format('dd')}</small>
690698
</li>,
691699
);
692700
}
@@ -725,6 +733,7 @@ export default class DayPicker extends React.Component {
725733
onDayClick,
726734
onDayMouseEnter,
727735
onDayMouseLeave,
736+
firstDayOfWeek,
728737
renderMonth,
729738
renderDay,
730739
renderCalendarInfo,
@@ -842,6 +851,7 @@ export default class DayPicker extends React.Component {
842851
onMonthTransitionEnd={this.updateStateAfterMonthTransition}
843852
monthFormat={monthFormat}
844853
daySize={daySize}
854+
firstDayOfWeek={firstDayOfWeek}
845855
isFocused={shouldFocusDate}
846856
focusedDate={focusedDate}
847857
phrases={phrases}

src/components/DayPickerRangeController.jsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import toISOMonthString from '../utils/toISOMonthString';
2323

2424
import FocusedInputShape from '../shapes/FocusedInputShape';
2525
import ScrollableOrientationShape from '../shapes/ScrollableOrientationShape';
26+
import DayOfWeekShape from '../shapes/DayOfWeekShape';
2627

2728
import {
2829
START_DATE,
@@ -67,6 +68,7 @@ const propTypes = forbidExtraProps({
6768
onOutsideClick: PropTypes.func,
6869
renderDay: PropTypes.func,
6970
renderCalendarInfo: PropTypes.func,
71+
firstDayOfWeek: DayOfWeekShape,
7072

7173
// accessibility
7274
onBlur: PropTypes.func,
@@ -114,6 +116,7 @@ const defaultProps = {
114116

115117
renderDay: null,
116118
renderCalendarInfo: null,
119+
firstDayOfWeek: null,
117120

118121
// accessibility
119122
onBlur() {},
@@ -806,6 +809,7 @@ export default class DayPickerRangeController extends React.Component {
806809
onOutsideClick,
807810
withPortal,
808811
enableOutsideDays,
812+
firstDayOfWeek,
809813
hideKeyboardShortcutsPanel,
810814
daySize,
811815
focusedInput,
@@ -843,6 +847,7 @@ export default class DayPickerRangeController extends React.Component {
843847
navNext={navNext}
844848
renderDay={renderDay}
845849
renderCalendarInfo={renderCalendarInfo}
850+
firstDayOfWeek={firstDayOfWeek}
846851
hideKeyboardShortcutsPanel={hideKeyboardShortcutsPanel}
847852
isFocused={isFocused}
848853
getFirstFocusableDay={this.getFirstFocusableDay}

src/components/DayPickerSingleDateController.jsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import toISODateString from '../utils/toISODateString';
1919
import toISOMonthString from '../utils/toISOMonthString';
2020

2121
import ScrollableOrientationShape from '../shapes/ScrollableOrientationShape';
22+
import DayOfWeekShape from '../shapes/DayOfWeekShape';
2223

2324
import {
2425
HORIZONTAL_ORIENTATION,
@@ -49,6 +50,7 @@ const propTypes = forbidExtraProps({
4950
orientation: ScrollableOrientationShape,
5051
withPortal: PropTypes.bool,
5152
initialVisibleMonth: PropTypes.func,
53+
firstDayOfWeek: DayOfWeekShape,
5254
hideKeyboardShortcutsPanel: PropTypes.bool,
5355
daySize: nonNegativeInteger,
5456

@@ -95,6 +97,7 @@ const defaultProps = {
9597
withPortal: false,
9698
hideKeyboardShortcutsPanel: false,
9799
initialVisibleMonth: null,
100+
firstDayOfWeek: null,
98101
daySize: DAY_SIZE,
99102

100103
navPrev: null,
@@ -539,6 +542,7 @@ export default class DayPickerSingleDateController extends React.Component {
539542
enableOutsideDays,
540543
hideKeyboardShortcutsPanel,
541544
daySize,
545+
firstDayOfWeek,
542546
renderDay,
543547
renderCalendarInfo,
544548
isFocused,
@@ -563,6 +567,7 @@ export default class DayPickerSingleDateController extends React.Component {
563567
hidden={!focused}
564568
hideKeyboardShortcutsPanel={hideKeyboardShortcutsPanel}
565569
initialVisibleMonth={() => currentMonth}
570+
firstDayOfWeek={firstDayOfWeek}
566571
navPrev={navPrev}
567572
navNext={navNext}
568573
renderMonth={renderMonth}

src/components/SingleDatePicker.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const defaultProps = {
5757
withPortal: false,
5858
withFullScreenPortal: false,
5959
initialVisibleMonth: null,
60+
firstDayOfWeek: null,
6061
numberOfMonths: 2,
6162
keepOpenOnDateSelect: false,
6263
reopenPickerOnClearDate: false,
@@ -315,6 +316,7 @@ export default class SingleDatePicker extends React.Component {
315316
renderDay,
316317
renderCalendarInfo,
317318
hideKeyboardShortcutsPanel,
319+
firstDayOfWeek,
318320
customCloseIcon,
319321
phrases,
320322
daySize,
@@ -360,6 +362,7 @@ export default class SingleDatePicker extends React.Component {
360362
isOutsideRange={isOutsideRange}
361363
isDayBlocked={isDayBlocked}
362364
isDayHighlighted={isDayHighlighted}
365+
firstDayOfWeek={firstDayOfWeek}
363366
/>
364367

365368
{withFullScreenPortal && (

src/shapes/DateRangePickerShape.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import getPhrasePropTypes from '../utils/getPhrasePropTypes';
88
import FocusedInputShape from '../shapes/FocusedInputShape';
99
import OrientationShape from '../shapes/OrientationShape';
1010
import anchorDirectionShape from '../shapes/AnchorDirectionShape';
11+
import DayOfWeekShape from '../shapes/DayOfWeekShape';
1112

1213
export default {
1314
// required props for a functional interactive DateRangePicker
@@ -44,7 +45,7 @@ export default {
4445
withFullScreenPortal: PropTypes.bool,
4546
daySize: nonNegativeInteger,
4647
isRTL: PropTypes.bool,
47-
48+
firstDayOfWeek: DayOfWeekShape,
4849
initialVisibleMonth: PropTypes.func,
4950
numberOfMonths: PropTypes.number,
5051
keepOpenOnDateSelect: PropTypes.bool,

0 commit comments

Comments
 (0)