Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor DatePicker to use React hooks #22897

Closed
wants to merge 3 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 39 additions & 52 deletions packages/components/src/date-time/date.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,34 @@ import DayPickerSingleDateController from 'react-dates/lib/components/DayPickerS
/**
* WordPress dependencies
*/
import { Component, createRef } from '@wordpress/element';
import { 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 );
}
function DatePicker( { currentDate, isInvalidDate, onChange } ) {
const nodeRef = createRef();
truchot marked this conversation as resolved.
Show resolved Hide resolved

/*
* 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 ) {
const keepFocusInside = () => {
if ( ! nodeRef.current ) {
return;
}
// If focus was lost.
if (
! document.activeElement ||
! this.nodeRef.current.contains( document.activeElement )
! nodeRef.current.contains( document.activeElement )
) {
// Retrieve the focus region div.
const focusRegion = this.nodeRef.current.querySelector(
const focusRegion = nodeRef.current.querySelector(
'.DayPicker_focusRegion'
);
if ( ! focusRegion ) {
Expand All @@ -51,11 +45,9 @@ class DatePicker extends Component {
// Keep the focus on focus region.
focusRegion.focus();
}
}

onChangeMoment( newDate ) {
const { currentDate, onChange } = this.props;
};

const onChangeMoment = ( newDate ) => {
// If currentDate is null, use now as momentTime to designate hours, minutes, seconds.
const momentDate = currentDate ? moment( currentDate ) : moment();
const momentTime = {
Expand All @@ -65,54 +57,49 @@ class DatePicker extends Component {
};

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 ) {
const getMomentDate = () => {
if ( null === currentDate ) {
return null;
}
return currentDate ? moment( currentDate ) : moment();
}

render() {
const { currentDate, isInvalidDate } = this.props;
};

const momentDate = this.getMomentDate( currentDate );
const momentDate = getMomentDate();

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() );
} }
onPrevMonthClick={ this.keepFocusInside }
onNextMonthClick={ this.keepFocusInside }
/>
</div>
);
}
return (
<div className="components-datetime__date" ref={ 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={ onChangeMoment }
transitionDuration={ 0 }
weekDayFormat="ddd"
isRTL={ isRTL() }
isOutsideRange={ ( date ) => {
return isInvalidDate && isInvalidDate( date.toDate() );
} }
onPrevMonthClick={ keepFocusInside }
onNextMonthClick={ keepFocusInside }
/>
</div>
);
}

export default DatePicker;