Merge pull request woocommerce/woocommerce-admin#235 from woocommerce/add/custom-datepicker-styles
Add custom Datepicker styles and validation
This commit is contained in:
commit
bf9eb38ab0
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Component, Fragment } from '@wordpress/element';
|
||||
import { Component } from '@wordpress/element';
|
||||
import moment from 'moment';
|
||||
import {
|
||||
DayPickerRangeController,
|
||||
|
@ -19,11 +19,11 @@ import 'react-dates/lib/css/_datepicker.css';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import { toMoment } from 'lib/date';
|
||||
import DateInput from './input';
|
||||
import phrases from './phrases';
|
||||
import './style.scss';
|
||||
|
||||
const START_DATE = 'startDate';
|
||||
const END_DATE = 'endDate';
|
||||
|
||||
// 782px is the width designated by Gutenberg's `</ Popover>` component.
|
||||
// * https://github.com/WordPress/gutenberg/blob/c8f8806d4465a83c1a0bc62d5c61377b56fa7214/components/popover/utils.js#L6
|
||||
|
@ -39,6 +39,8 @@ class DateRange extends Component {
|
|||
focusedInput: START_DATE,
|
||||
afterText: after ? after.format( shortDateFormat ) : '',
|
||||
beforeText: before ? before.format( shortDateFormat ) : '',
|
||||
afterError: null,
|
||||
beforeError: null,
|
||||
};
|
||||
|
||||
this.onDatesChange = this.onDatesChange.bind( this );
|
||||
|
@ -47,10 +49,31 @@ class DateRange extends Component {
|
|||
this.getOutsideRange = this.getOutsideRange.bind( this );
|
||||
}
|
||||
|
||||
componentDidUpdate( prevProps ) {
|
||||
const { after, before } = this.props;
|
||||
/**
|
||||
* Check if props have been reset. If so, reset internal state. Disabling
|
||||
* eslint here because this setState cannot cause infinte loop
|
||||
*/
|
||||
/* eslint-disable react/no-did-update-set-state */
|
||||
if ( ( prevProps.before || prevProps.after ) && ( null === after && null === before ) ) {
|
||||
this.setState( {
|
||||
focusedInput: START_DATE,
|
||||
afterText: '',
|
||||
beforeText: '',
|
||||
afterError: null,
|
||||
beforeError: null,
|
||||
} );
|
||||
}
|
||||
/* eslint-enable react/no-did-update-set-state */
|
||||
}
|
||||
|
||||
onDatesChange( { startDate, endDate } ) {
|
||||
this.setState( {
|
||||
afterText: startDate ? startDate.format( shortDateFormat ) : '',
|
||||
beforeText: endDate ? endDate.format( shortDateFormat ) : '',
|
||||
afterError: null,
|
||||
beforeError: null,
|
||||
} );
|
||||
this.props.onSelect( {
|
||||
after: startDate,
|
||||
|
@ -64,16 +87,47 @@ class DateRange extends Component {
|
|||
} );
|
||||
}
|
||||
|
||||
getValidatedDate( input, value ) {
|
||||
const { after, before } = this.props;
|
||||
const date = toMoment( shortDateFormat, value );
|
||||
if ( ! date ) {
|
||||
return {
|
||||
date: null,
|
||||
error: __( 'Invalid date', 'wc-admin' ),
|
||||
};
|
||||
}
|
||||
if ( moment().isBefore( date, 'day' ) ) {
|
||||
return {
|
||||
date: null,
|
||||
error: __( 'Select a date in the past', 'wc-admin' ),
|
||||
};
|
||||
}
|
||||
if ( 'after' === input && before && date.isAfter( before, 'day' ) ) {
|
||||
return {
|
||||
date: null,
|
||||
error: __( 'Start date must be before end date', 'wc-admin' ),
|
||||
};
|
||||
}
|
||||
if ( 'before' === input && after && date.isBefore( after, 'day' ) ) {
|
||||
return {
|
||||
date: null,
|
||||
error: __( 'Start date must be before end date', 'wc-admin' ),
|
||||
};
|
||||
}
|
||||
return { date };
|
||||
}
|
||||
|
||||
onInputChange( input, event ) {
|
||||
const value = event.target.value;
|
||||
this.setState( { [ input + 'Text' ]: value } );
|
||||
const date = toMoment( shortDateFormat, value );
|
||||
if ( date ) {
|
||||
const { date, error } = this.getValidatedDate( input, value );
|
||||
this.setState( {
|
||||
[ input + 'Text' ]: value,
|
||||
[ input + 'Error' ]: value.length > 0 ? error : null,
|
||||
} );
|
||||
this.props.onSelect( {
|
||||
[ input ]: date,
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
getOutsideRange() {
|
||||
const { inValidDays } = this.props;
|
||||
|
@ -91,77 +145,78 @@ class DateRange extends Component {
|
|||
return 'function' === typeof inValidDays ? inValidDays : undefined;
|
||||
}
|
||||
|
||||
setTnitialVisibleMonth( isDoubleCalendar, before ) {
|
||||
return () => {
|
||||
const visibleDate = before || moment();
|
||||
if ( isDoubleCalendar ) {
|
||||
return visibleDate.clone().subtract( 1, 'month' );
|
||||
}
|
||||
return visibleDate;
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { focusedInput, afterText, beforeText } = this.state;
|
||||
const { focusedInput, afterText, beforeText, afterError, beforeError } = this.state;
|
||||
const { after, before } = this.props;
|
||||
const isOutsideRange = this.getOutsideRange();
|
||||
const isMobile = isMobileViewport();
|
||||
const isDoubleCalendar = isMobile && window.innerWidth > 624;
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="woocommerce-date-picker__date-inputs">
|
||||
<input
|
||||
<div
|
||||
className={ classnames( 'woocommerce-calendar', {
|
||||
'is-mobile': isMobile,
|
||||
} ) }
|
||||
>
|
||||
<div className="woocommerce-calendar__inputs">
|
||||
<DateInput
|
||||
value={ afterText }
|
||||
type="text"
|
||||
onChange={ partial( this.onInputChange, 'after' ) }
|
||||
aria-label={ __( 'Start Date', 'wc-admin' ) }
|
||||
id="after-date-string"
|
||||
aria-describedby="after-date-string-message"
|
||||
/>
|
||||
<p className="screen-reader-text" id="after-date-string-message">
|
||||
{ sprintf(
|
||||
dateFormat={ shortDateFormat }
|
||||
label={ __( 'Start Date', 'wc-admin' ) }
|
||||
error={ afterError }
|
||||
describedBy={ sprintf(
|
||||
__(
|
||||
"Date input describing a selected date range's start date in format %s",
|
||||
'wc-admin'
|
||||
),
|
||||
shortDateFormat
|
||||
) }
|
||||
</p>
|
||||
<span>{ __( 'to', 'wc-admin' ) }</span>
|
||||
<input
|
||||
value={ beforeText }
|
||||
type="text"
|
||||
onChange={ partial( this.onInputChange, 'before' ) }
|
||||
aria-label={ __( 'End Date', 'wc-admin' ) }
|
||||
id="before-date-string"
|
||||
aria-describedby="before-date-string-message"
|
||||
/>
|
||||
<p className="screen-reader-text" id="before-date-string-message">
|
||||
{ sprintf(
|
||||
<div className="woocommerce-calendar__inputs-to">{ __( 'to', 'wc-admin' ) }</div>
|
||||
<DateInput
|
||||
value={ beforeText }
|
||||
onChange={ partial( this.onInputChange, 'before' ) }
|
||||
dateFormat={ shortDateFormat }
|
||||
label={ __( 'End Date', 'wc-admin' ) }
|
||||
error={ beforeError }
|
||||
describedBy={ sprintf(
|
||||
__(
|
||||
"Date input describing a selected date range's end date in format %s",
|
||||
'wc-admin'
|
||||
),
|
||||
shortDateFormat
|
||||
) }
|
||||
</p>
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={ classnames( 'woocommerce-calendar', {
|
||||
'is-mobile': isMobile,
|
||||
} ) }
|
||||
>
|
||||
<div className="woocommerce-calendar__react-dates">
|
||||
<DayPickerRangeController
|
||||
onDatesChange={ this.onDatesChange }
|
||||
onFocusChange={ this.onFocusChange }
|
||||
focusedInput={ focusedInput }
|
||||
startDate={ after }
|
||||
startDateId={ START_DATE }
|
||||
startDatePlaceholderText={ 'Start Date' }
|
||||
endDate={ before }
|
||||
endDateId={ END_DATE }
|
||||
endDatePlaceholderText={ 'End Date' }
|
||||
orientation={ 'horizontal' }
|
||||
numberOfMonths={ 1 }
|
||||
numberOfMonths={ isDoubleCalendar ? 2 : 1 }
|
||||
isOutsideRange={ isOutsideRange }
|
||||
minimumNights={ 0 }
|
||||
hideKeyboardShortcutsPanel
|
||||
noBorder
|
||||
initialVisibleMonth={ () => after || moment() }
|
||||
initialVisibleMonth={ this.setTnitialVisibleMonth( isDoubleCalendar, before ) }
|
||||
phrases={ phrases }
|
||||
firstDayOfWeek={ Number( wcSettings.date.dow ) }
|
||||
/>
|
||||
</div>
|
||||
</Fragment>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/** @format */
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Dashicon, Popover } from '@wordpress/components';
|
||||
import classnames from 'classnames';
|
||||
import { uniqueId } from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const DateInput = ( { value, onChange, dateFormat, label, describedBy, error } ) => {
|
||||
const classes = classnames( 'woocommerce-calendar__input', {
|
||||
'is-empty': value.length === 0,
|
||||
'is-error': error,
|
||||
} );
|
||||
const id = uniqueId( '_woo-dates-input' );
|
||||
return (
|
||||
<div className={ classes }>
|
||||
<input
|
||||
type="text"
|
||||
className="woocommerce-calendar__input-text"
|
||||
value={ value }
|
||||
onChange={ onChange }
|
||||
aria-label={ label }
|
||||
id={ id }
|
||||
aria-describedby={ `${ id }-message` }
|
||||
placeholder={ dateFormat.toLowerCase() }
|
||||
/>
|
||||
{ error && (
|
||||
<Popover
|
||||
className="woocommerce-calendar__input-error"
|
||||
focusOnMount={ false }
|
||||
position="bottom center"
|
||||
>
|
||||
{ error }
|
||||
</Popover>
|
||||
) }
|
||||
<Dashicon icon="calendar" />
|
||||
<p className="screen-reader-text" id={ `${ id }-message` }>
|
||||
{ error || describedBy }
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
DateInput.propTypes = {
|
||||
value: PropTypes.string,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
dateFormat: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
describedBy: PropTypes.string.isRequired,
|
||||
error: PropTypes.string,
|
||||
};
|
||||
|
||||
export default DateInput;
|
|
@ -1,6 +1,20 @@
|
|||
/** @format */
|
||||
|
||||
.woocommerce-calendar {
|
||||
width: 100%;
|
||||
background-color: $core-grey-light-100;
|
||||
border-top: 1px solid $core-grey-light-700;
|
||||
height: 396px;
|
||||
|
||||
&.is-mobile {
|
||||
height: 100%;
|
||||
min-height: 537px;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-calendar__react-dates {
|
||||
width: 100%;
|
||||
|
||||
.DayPicker {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
@ -9,11 +23,127 @@
|
|||
margin-top: 10px;
|
||||
}
|
||||
|
||||
&.is-mobile {
|
||||
height: 360px;
|
||||
.CalendarDay__selected_span {
|
||||
background: $woocommerce;
|
||||
border: 1px solid $core-grey-light-700;
|
||||
}
|
||||
|
||||
.CalendarDay__selected {
|
||||
background: $woocommerce-700;
|
||||
border: 1px solid $core-grey-light-700;
|
||||
}
|
||||
|
||||
.CalendarDay__hovered_span {
|
||||
background: $woocommerce;
|
||||
border: 1px solid $core-grey-light-500;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.CalendarDay__blocked_out_of_range {
|
||||
color: $core-grey-light-900;
|
||||
}
|
||||
|
||||
.DayPicker_transitionContainer,
|
||||
.CalendarMonthGrid,
|
||||
.CalendarMonth,
|
||||
.DayPicker {
|
||||
width: 318px;
|
||||
background-color: $core-grey-light-100;
|
||||
}
|
||||
|
||||
.DayPicker_weekHeader_li {
|
||||
color: $core-grey-dark-400;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-calendar__inputs {
|
||||
padding: 1em;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
display: grid;
|
||||
grid-template-columns: 43% 14% 43%;
|
||||
margin: 0 auto;
|
||||
|
||||
.components-base-control {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-calendar__inputs-to {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.woocommerce-calendar__input {
|
||||
position: relative;
|
||||
|
||||
.dashicons-calendar {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 10px;
|
||||
|
||||
path {
|
||||
fill: $core-grey-dark-300;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-empty {
|
||||
.dashicons-calendar path {
|
||||
fill: $core-grey-dark-300;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-error {
|
||||
.dashicons-calendar path {
|
||||
fill: $error-red;
|
||||
}
|
||||
|
||||
.woocommerce-calendar__input-text {
|
||||
border: 1px solid $error-red;
|
||||
box-shadow: inset 0px 0px 8px $error-red;
|
||||
|
||||
&:focus {
|
||||
box-shadow: inset 0px 0px 8px $error-red, 0 0 6px rgba(30, 140, 190, 0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-calendar__input-text {
|
||||
color: $core-grey-dark-500;
|
||||
border-radius: 3px;
|
||||
padding: 10px 10px 10px 30px;
|
||||
width: 100%;
|
||||
@include font-size( 13 );
|
||||
|
||||
&::placeholder {
|
||||
color: $core-grey-dark-300;
|
||||
}
|
||||
|
||||
&:focus + span .woocommerce-calendar__input-error {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-calendar__input-error {
|
||||
display: none;
|
||||
|
||||
.components-popover__content {
|
||||
background-color: $core-grey-dark-400;
|
||||
color: $white;
|
||||
padding: 0.5em;
|
||||
border: none;
|
||||
}
|
||||
|
||||
&.components-popover {
|
||||
.components-popover__content {
|
||||
min-width: 100px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&:not(.no-arrow):after {
|
||||
border-color: $core-grey-dark-400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import { __ } from '@wordpress/i18n';
|
|||
import { Component, Fragment } from '@wordpress/element';
|
||||
import { TabPanel, Button } from '@wordpress/components';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -16,6 +17,8 @@ import PresetPeriods from './preset-periods';
|
|||
import Link from 'components/link';
|
||||
import { DateRange } from 'components/calendar';
|
||||
|
||||
const isMobileViewport = () => window.innerWidth < 782;
|
||||
|
||||
class DatePickerContent extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
@ -44,9 +47,10 @@ class DatePickerContent extends Component {
|
|||
onClose,
|
||||
getUpdatePath,
|
||||
isValidSelection,
|
||||
resetCustomValues,
|
||||
} = this.props;
|
||||
return (
|
||||
<Fragment>
|
||||
<div>
|
||||
<H className="screen-reader-text" tabIndex="0">
|
||||
{ __( 'Select date range and comparison', 'wc-admin' ) }
|
||||
</H>
|
||||
|
@ -89,26 +93,53 @@ class DatePickerContent extends Component {
|
|||
inValidDays="future"
|
||||
/>
|
||||
) }
|
||||
<H className="woocommerce-date-picker__text">{ __( 'compare to', 'wc-admin' ) }</H>
|
||||
<div
|
||||
className={ classnames( 'woocommerce-date-picker__content-controls', {
|
||||
'is-sticky-bottom': selectedTab === 'custom' && isMobileViewport(),
|
||||
'is-custom': selectedTab === 'custom',
|
||||
} ) }
|
||||
>
|
||||
<H className="woocommerce-date-picker__text">
|
||||
{ __( 'compare to', 'wc-admin' ) }
|
||||
</H>
|
||||
<ComparePeriods onSelect={ onSelect } compare={ compare } />
|
||||
<div className="woocommerce-date-picker__content-controls-btns">
|
||||
{ selectedTab === 'custom' && (
|
||||
<Button
|
||||
className="woocommerce-date-picker__content-controls-btn"
|
||||
isPrimary
|
||||
onClick={ resetCustomValues }
|
||||
disabled={ ! ( after || before ) }
|
||||
>
|
||||
{ __( 'Reset', 'wc-admin' ) }
|
||||
</Button>
|
||||
) }
|
||||
{ isValidSelection( selectedTab ) ? (
|
||||
<Link
|
||||
className="woocommerce-date-picker__update-btn components-button is-button is-primary"
|
||||
to={ getUpdatePath( selectedTab ) }
|
||||
/* eslint-disable max-len */
|
||||
className="woocommerce-date-picker__content-controls-btn components-button is-button is-primary"
|
||||
/* eslint-enable max-len */
|
||||
href={ getUpdatePath( selectedTab ) }
|
||||
onClick={ onClose }
|
||||
>
|
||||
{ __( 'Update', 'wc-admin' ) }
|
||||
</Link>
|
||||
) : (
|
||||
<Button className="woocommerce-date-picker__update-btn" isPrimary disabled>
|
||||
<Button
|
||||
className="woocommerce-date-picker__content-controls-btn"
|
||||
isPrimary
|
||||
disabled
|
||||
>
|
||||
{ __( 'Update', 'wc-admin' ) }
|
||||
</Button>
|
||||
) }
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
) }
|
||||
</TabPanel>
|
||||
</Section>
|
||||
</Fragment>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -119,6 +150,7 @@ DatePickerContent.propTypes = {
|
|||
onSelect: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
getUpdatePath: PropTypes.func.isRequired,
|
||||
resetCustomValues: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default DatePickerContent;
|
||||
|
|
|
@ -23,6 +23,7 @@ class DatePicker extends Component {
|
|||
this.select = this.select.bind( this );
|
||||
this.getUpdatePath = this.getUpdatePath.bind( this );
|
||||
this.isValidSelection = this.isValidSelection.bind( this );
|
||||
this.resetCustomValues = this.resetCustomValues.bind( this );
|
||||
}
|
||||
|
||||
// @TODO change this to `getDerivedStateFromProps` in React 16.4
|
||||
|
@ -73,6 +74,13 @@ class DatePicker extends Component {
|
|||
return true;
|
||||
}
|
||||
|
||||
resetCustomValues() {
|
||||
this.setState( {
|
||||
after: null,
|
||||
before: null,
|
||||
} );
|
||||
}
|
||||
|
||||
render() {
|
||||
const { period, compare, after, before } = this.state;
|
||||
return (
|
||||
|
@ -99,6 +107,7 @@ class DatePicker extends Component {
|
|||
onClose={ onClose }
|
||||
getUpdatePath={ this.getUpdatePath }
|
||||
isValidSelection={ this.isValidSelection }
|
||||
resetCustomValues={ this.resetCustomValues }
|
||||
/>
|
||||
) }
|
||||
/>
|
||||
|
|
|
@ -13,25 +13,12 @@
|
|||
}
|
||||
|
||||
.woocommerce-date-picker__content {
|
||||
.components-popover__content {
|
||||
> .components-popover__content {
|
||||
width: 320px;
|
||||
padding: 1em 0;
|
||||
border: 1px solid $gray;
|
||||
background-color: $white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
& > * {
|
||||
margin: 0 0 1em 0;
|
||||
|
||||
&:last-child {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.is-mobile {
|
||||
.components-popover__content {
|
||||
& > .components-popover__content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
@ -44,19 +31,16 @@
|
|||
.components-popover__close {
|
||||
transform: translateY(22px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-date-picker__date-inputs {
|
||||
max-width: 320px;
|
||||
width: 100%;
|
||||
display: grid;
|
||||
margin: 0 1em 1em 1em;
|
||||
grid-template-columns: 45% 10% 45%;
|
||||
text-align: center;
|
||||
.components-tab-panel__tab-content {
|
||||
height: calc(100% - 38px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-date-picker__tabs {
|
||||
height: calc(100% - 42px);
|
||||
|
||||
.components-tab-panel__tabs {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
|
@ -68,14 +52,6 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
& > * {
|
||||
margin: 0 0 1em 0;
|
||||
|
||||
&:last-child {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,21 +77,45 @@
|
|||
}
|
||||
}
|
||||
|
||||
.woocommerce-date-picker__update-btn {
|
||||
border: 1px solid $gray;
|
||||
background-color: transparent;
|
||||
padding: 0.5em;
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
justify-content: center;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.woocommerce-date-picker__text {
|
||||
@include font-size( 12 );
|
||||
font-weight: 100;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
color: $core-grey-dark-500;
|
||||
color: $core-grey-dark-300;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
background-color: $white;
|
||||
}
|
||||
|
||||
.woocommerce-date-picker__content-controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
padding-bottom: 1em;
|
||||
background-color: $white;
|
||||
|
||||
&.is-custom {
|
||||
border-top: 1px solid $core-grey-light-700;
|
||||
}
|
||||
|
||||
&.is-sticky-bottom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-date-picker__content-controls-btns {
|
||||
padding-top: 1em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.woocommerce-date-picker__content-controls-btn {
|
||||
justify-content: center;
|
||||
width: 50%;
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ export function toMoment( format, str ) {
|
|||
}
|
||||
if ( 'string' === typeof str ) {
|
||||
const date = moment( str, [ isoDateFormat, format ], true );
|
||||
return date.isValid ? date : null;
|
||||
return date.isValid() ? date : null;
|
||||
}
|
||||
throw new Error( 'toMoment requires a string to be passed as an argument' );
|
||||
}
|
||||
|
|
|
@ -51,6 +51,11 @@ describe( 'toMoment', () => {
|
|||
const fn = () => toMoment( '', 77 );
|
||||
expect( fn ).toThrow();
|
||||
} );
|
||||
|
||||
it( 'shoud return null on invalid date', () => {
|
||||
const invalidDate = toMoment( 'YYYY', '2018-00-00' );
|
||||
expect( invalidDate ).toBe( null );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'getCurrentPeriod', () => {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue