diff --git a/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-1-snap.png b/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-1-snap.png index 07b24b64..83531f49 100644 Binary files a/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-1-snap.png and b/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-1-snap.png differ diff --git a/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-open-date-1-snap.png b/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-open-date-1-snap.png index ccf5548a..064eb313 100644 Binary files a/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-open-date-1-snap.png and b/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-open-date-1-snap.png differ diff --git a/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-open-datetime-1-snap.png b/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-open-datetime-1-snap.png index e5fb22d9..b25922cd 100644 Binary files a/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-open-datetime-1-snap.png and b/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-open-datetime-1-snap.png differ diff --git a/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-open-month-picker-1-snap.png b/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-open-month-picker-1-snap.png new file mode 100644 index 00000000..4130827c Binary files /dev/null and b/e2e/__tests__/__image_snapshots__/date-input-test-js-components-date-input-common-open-month-picker-1-snap.png differ diff --git a/e2e/__tests__/date-input.test.js b/e2e/__tests__/date-input.test.js index 6bc915a0..7b429986 100644 --- a/e2e/__tests__/date-input.test.js +++ b/e2e/__tests__/date-input.test.js @@ -18,6 +18,16 @@ const SUITES = [ await input.click(); + await (await iframe.waitForXPath('//input')).click(); + await input.click(); + }), + baisy.suite('Components/DateInput', 'common', 'open month picker') + .setRootHeight(600) + .setEnhancer(async (iframe) => { + const input = await iframe.waitForXPath('(//input)[7]'); + + await input.click(); + await (await iframe.waitForXPath('//input')).click(); await input.click(); }), diff --git a/src/components/DateInput/DateInput.js b/src/components/DateInput/DateInput.js index e369d3f7..f592b059 100644 --- a/src/components/DateInput/DateInput.js +++ b/src/components/DateInput/DateInput.js @@ -17,6 +17,7 @@ type DateInputProps = { stretch?: boolean, clearable?: boolean, disabled?: boolean, + isMonthPicker?: boolean, placeholder?: string, }; @@ -34,24 +35,34 @@ class DateInput extends React.Component { constructor(props: DateInputProps) { super(props); + const dateFormat = this.getDateFormat(); + this.state = { - textValue: utils.fromISOToViewFormat(props.value, props.withTime), + textValue: utils.fromISOToViewFormat(props.value, dateFormat), isOpen: false, }; } componentDidUpdate(prevProps: DateInputProps) { - const { value, withTime } = this.props; + const { value } = this.props; + const dateFormat = this.getDateFormat(); if (value !== prevProps.value) { this.setState({ - textValue: utils.fromISOToViewFormat(value, withTime), + textValue: utils.fromISOToViewFormat(value, dateFormat), }); } } + getDateFormat() { + const { isMonthPicker, withTime } = this.props; + + return isMonthPicker ? utils.YEAR_MONTH_FORMAT : withTime ? utils.DATETIME_FORMAT : utils.DATE_FORMAT; + } + onChangeText = ({ target: { value }}: Object) => { const { withTime } = this.props; + const dateFormat = this.getDateFormat(); this.setState({ textValue: value }); @@ -59,7 +70,7 @@ class DateInput extends React.Component { this.props.onChange(null); return; } else { - const luxonValue = utils.fromViewFormatToLuxon(value, withTime); + const luxonValue = utils.fromViewFormatToLuxon(value, dateFormat); if (luxonValue && luxonValue.isValid) { value = utils.fromLuxonToISO(luxonValue, withTime); @@ -70,13 +81,13 @@ class DateInput extends React.Component { }; onBlur = () => { - const { withTime } = this.props; const { textValue } = this.state; + const dateFormat = this.getDateFormat(); - const luxonValue = utils.fromViewFormatToLuxon(textValue, withTime); + const luxonValue = utils.fromViewFormatToLuxon(textValue, dateFormat); if (luxonValue && !luxonValue.isValid) { - this.setState({ textValue: utils.fromISOToViewFormat(this.props.value, withTime) }); + this.setState({ textValue: utils.fromISOToViewFormat(this.props.value, dateFormat) }); } } @@ -93,17 +104,17 @@ class DateInput extends React.Component { }; collectProps() { - const { value, withTime, withPortal, ...rest } = this.props; - - const dateFormat = withTime ? utils.DATETIME_FORMAT : utils.DATE_FORMAT; + const { value, withTime, withPortal, isMonthPicker, ...rest } = this.props; return { selected: utils.fromISOtoJSDate(value), - dateFormat, + dateFormat: this.getDateFormat(), ...rest, showTimeSelect: withTime, + showMonthYearPicker: isMonthPicker, onChange: this.onChangeDate, inline: true, + todayButton: isMonthPicker ? 'Current' : 'Today', }; } @@ -122,10 +133,10 @@ class DateInput extends React.Component { render() { const collectedProps = this.collectProps(); - const { value, withTime, withPortal, stretch, onChange, clearable, disabled, placeholder, ...rest } = this.props; + const { value, withTime, withPortal, stretch, onChange, clearable, disabled, placeholder, isMonthPicker, ...rest } = this.props; const { textValue, isOpen } = this.state; - const mask = withTime ? utils.DATETIME_MASK : utils.DATE_MASK; + const mask = isMonthPicker ? utils.YEAR_MONTH_MASK : withTime ? utils.DATETIME_MASK : utils.DATE_MASK; return ( { boundariesElement: 'viewport', }, }}> - + ); diff --git a/src/components/DateInput/DateInput.stories.js b/src/components/DateInput/DateInput.stories.js index 6605e40f..17705323 100644 --- a/src/components/DateInput/DateInput.stories.js +++ b/src/components/DateInput/DateInput.stories.js @@ -27,6 +27,9 @@ export default (asStory) => { + + + )); }); diff --git a/src/components/DateInput/DateInput.theme.js b/src/components/DateInput/DateInput.theme.js index 9f1b4e48..5eba2bc2 100644 --- a/src/components/DateInput/DateInput.theme.js +++ b/src/components/DateInput/DateInput.theme.js @@ -1,13 +1,18 @@ +import { css } from '@emotion/core'; + import { createThemeTag } from '../../theme/createThemeTag'; // eslint-disable-next-line const [_, theme] = createThemeTag('dateInput', ({ COLORS }: *) => ({ - globals: ` + globals: css` .react-datepicker { border: 1px solid ${COLORS.PRIMARY_BORDER_COLOR}; - box-shadow: 0 2px 10px 0 rgba(208,215,221,0.5); + box-shadow: 0 2px 10px 0 rgba(208, 215, 221, 0.5); display: flex; padding-bottom: 32px; + font-size: 12px; + font-family: inherit; + color: ${COLORS.PRIMARY_TEXT_COLOR}; } .react-datepicker__header, @@ -31,8 +36,6 @@ const [_, theme] = createThemeTag('dateInput', ({ COLORS }: *) => ({ display: flex; justify-content: center; align-items: center; - font-size: 12px; - font-family: Poppins; color: ${COLORS.PRIMARY_TEXT_COLOR}; } @@ -44,25 +47,22 @@ const [_, theme] = createThemeTag('dateInput', ({ COLORS }: *) => ({ display: flex; justify-content: center; align-items: center; - font-size: 12px; - font-family: Poppins; color: ${COLORS.PRIMARY_TEXT_COLOR}; margin-left: 4px; margin-right: 4px; } - .react-datepicker__day--selected { - border-radius: 24px; - background-color: ${COLORS.LIGHT_BLUE}; - color: ${COLORS.LIGHT_PRIMARY_TEXT_COLOR}; - } - .react-datepicker__day:hover { border-radius: 24px; } - .react-datepicker__time-list-item--selected { - background-color: ${COLORS.LIGHT_BLUE} !important; + .react-datepicker__time-container + .react-datepicker__time + .react-datepicker__time-box + ul.react-datepicker__time-list + li.react-datepicker__time-list-item--selected { + background-color: ${COLORS.LIGHT_BLUE}; + font-weight: 600; } .react-datepicker__week { @@ -85,57 +85,75 @@ const [_, theme] = createThemeTag('dateInput', ({ COLORS }: *) => ({ .react-datepicker__header--time { border-bottom: 1px solid ${COLORS.PRIMARY_BORDER_COLOR}; + height: 32px; } .react-datepicker-time__header { font-size: 12px; - font-family: Poppins; color: ${COLORS.PRIMARY_TEXT_COLOR}; font-weight: 600; } .react-datepicker__day--today { - font-size: 12px; - font-family: Poppins; color: ${COLORS.PRIMARY_TEXT_COLOR}; font-weight: 600; } + .react-datepicker__day--selected { + border-radius: 24px; + background-color: ${COLORS.LIGHT_BLUE}; + color: ${COLORS.LIGHT_PRIMARY_TEXT_COLOR}; + } + .react-datepicker__today-button { position: absolute; bottom: 0; width: 100%; height: 32px; - font-size: 12px; - font-family: Poppins; - color: ${COLORS.PRIMARY_TEXT_COLOR}; font-weight: 600; border-top: 1px solid ${COLORS.PRIMARY_BORDER_COLOR}; } .react-datepicker__header { - padding: 0; - height: 64px; + border-bottom: 1px solid ${COLORS.PRIMARY_BORDER_COLOR}; + padding-top: 6px; } .react-datepicker__day-names { - height: 32px; - font-size: 12px; display: flex; - border-bottom: 1px solid ${COLORS.PRIMARY_BORDER_COLOR}; + margin-top: 6px; } - .react-datepicker__current-month { + .react-datepicker-year-header { + padding-bottom: 6px; + } + + .react-datepicker__current-month, + .react-datepicker-year-header { font-size: 13px; font-weight: 600; - font-family: Poppins; color: ${COLORS.PRIMARY_TEXT_COLOR}; } + .react-datepicker__month-wrapper { + display: flex; + } + + .react-datepicker__month-text { + flex: 1; + padding: 6px 0; + } + + .react-datepicker__month--selected, + .react-datepicker__month--in-selecting-range, + .react-datepicker__month--in-range { + background-color: ${COLORS.LIGHT_BLUE}; + color: ${COLORS.LIGHT_PRIMARY_TEXT_COLOR}; + } + .react-datepicker__time-list-item { align-items: center; display: flex; - font-size: 12px; height: 32px !important; justify-content: center; padding: 0 !important; @@ -145,7 +163,6 @@ const [_, theme] = createThemeTag('dateInput', ({ COLORS }: *) => ({ .react-datepicker__current-month { align-items: center; display: flex; - height: 32px; justify-content: center; padding: 0; } diff --git a/src/components/DateInput/DateInput.utils.js b/src/components/DateInput/DateInput.utils.js index 2f85f3d3..52819f74 100644 --- a/src/components/DateInput/DateInput.utils.js +++ b/src/components/DateInput/DateInput.utils.js @@ -2,18 +2,20 @@ import { DateTime } from 'luxon'; +export const YEAR_MONTH_MASK = '99/9999'; export const DATE_MASK = '99/99/9999'; export const DATETIME_MASK = '99/99/9999, 99:99 aa'; +export const YEAR_MONTH_FORMAT = 'MM/yyyy'; export const DATE_FORMAT = 'MM/dd/yyyy'; export const DATETIME_FORMAT = 'MM/dd/yyyy, hh:mm a'; -export const fromISOToViewFormat = (value: ?string, withTime: ?boolean) => { +export const fromISOToViewFormat = (value: ?string, dateFormat: ?string) => { if (value) { value = DateTime.fromISO(value); if (value.isValid) { - value = value.toFormat(withTime ? DATETIME_FORMAT : DATE_FORMAT); + value = value.toFormat(dateFormat || DATE_FORMAT); } else { value = ''; } @@ -52,9 +54,9 @@ export const fromJSDateToISO = (value: ?Date, withTime: ?boolean) => { return value; }; -export const fromViewFormatToLuxon = (value: ?string, withTime: ?boolean) => { +export const fromViewFormatToLuxon = (value: ?string, dateFormat: ?string) => { if (value) { - value = DateTime.fromFormat(value, withTime ? DATETIME_FORMAT : DATE_FORMAT); + value = DateTime.fromFormat(value, dateFormat || DATE_FORMAT); } else { value = null; }