-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
Copy pathdate.js
135 lines (121 loc) · 3.9 KB
/
date.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/**
* External dependencies
*/
import moment from 'moment';
// react-dates doesn't tree-shake correctly, so we import from the individual
// component here, to avoid including too much of the library
import DayPickerSingleDateController from 'react-dates/lib/components/DayPickerSingleDateController';
/**
* WordPress dependencies
*/
import { Component, createRef } from '@wordpress/element';
/**
* Module Constants
*/
const TIMEZONELESS_FORMAT = 'YYYY-MM-DDTHH:mm:ss';
const isRTL = () => document.documentElement.dir === 'rtl';
class DatePicker extends Component {
constructor() {
super( ...arguments );
this.onChangeMoment = this.onChangeMoment.bind( this );
this.nodeRef = createRef();
this.keepFocusInside = this.keepFocusInside.bind( this );
this.isDayHighlighted = this.isDayHighlighted.bind( this );
}
/*
* Todo: We should remove this function ASAP.
* It is kept because focus is lost when we click on the previous and next month buttons.
* This focus loss closes the date picker popover.
* Ideally we should add an upstream commit on react-dates to fix this issue.
*/
keepFocusInside() {
if ( ! this.nodeRef.current ) {
return;
}
// If focus was lost.
if (
! document.activeElement ||
! this.nodeRef.current.contains( document.activeElement )
) {
// Retrieve the focus region div.
const focusRegion = this.nodeRef.current.querySelector(
'.DayPicker_focusRegion'
);
if ( ! focusRegion ) {
return;
}
// Keep the focus on focus region.
focusRegion.focus();
}
}
onChangeMoment( newDate ) {
const { currentDate, onChange } = this.props;
// If currentDate is null, use now as momentTime to designate hours, minutes, seconds.
const momentDate = currentDate ? moment( currentDate ) : moment();
const momentTime = {
hours: momentDate.hours(),
minutes: momentDate.minutes(),
seconds: 0,
};
onChange( newDate.set( momentTime ).format( TIMEZONELESS_FORMAT ) );
}
/**
* Create a Moment object from a date string. With no currentDate supplied, default to a Moment
* object representing now. If a null value is passed, return a null value.
*
* @param {?string} currentDate Date representing the currently selected date or null to signify no selection.
* @return {?moment.Moment} Moment object for selected date or null.
*/
getMomentDate( currentDate ) {
if ( null === currentDate ) {
return null;
}
return currentDate ? moment( currentDate ) : moment();
}
// todo change reference to `isDayHighlighted` every time, `events` prop change
isDayHighlighted( date ) {
// Do not highlight when no events.
if ( ! this.props.events?.length ) {
return false;
}
if ( this.props.onMonthPreviewed ) {
this.props.onMonthPreviewed( date.toDate() );
}
// Compare date against highlighted events.
return this.props.events.some( ( highlighted ) =>
date.isSame( highlighted.date, 'day' )
);
}
render() {
const { currentDate, isInvalidDate } = this.props;
const momentDate = this.getMomentDate( currentDate );
return (
<div className="components-datetime__date" ref={ this.nodeRef }>
<DayPickerSingleDateController
date={ momentDate }
daySize={ 30 }
focused
hideKeyboardShortcutsPanel
// This is a hack to force the calendar to update on month or year change
// https://github.com/airbnb/react-dates/issues/240#issuecomment-361776665
key={ `datepicker-controller-${
momentDate ? momentDate.format( 'MM-YYYY' ) : 'null'
}` }
noBorder
numberOfMonths={ 1 }
onDateChange={ this.onChangeMoment }
transitionDuration={ 0 }
weekDayFormat="ddd"
isRTL={ isRTL() }
isOutsideRange={ ( date ) => {
return isInvalidDate && isInvalidDate( date.toDate() );
} }
isDayHighlighted={ this.isDayHighlighted }
onPrevMonthClick={ this.keepFocusInside }
onNextMonthClick={ this.keepFocusInside }
/>
</div>
);
}
}
export default DatePicker;