diff --git a/packages/datetime/src/dateRangeInput.tsx b/packages/datetime/src/dateRangeInput.tsx index 318c5fe8f8..c6978bd980 100644 --- a/packages/datetime/src/dateRangeInput.tsx +++ b/packages/datetime/src/dateRangeInput.tsx @@ -36,7 +36,7 @@ import { Utils, } from "@blueprintjs/core"; -import { DateRange, isDateValid, isDayInRange } from "./common/dateUtils"; +import { areSameTime, DateRange, isDateValid, isDayInRange } from "./common/dateUtils"; import * as Errors from "./common/errors"; import { getFormattedDateString, IDateFormatProps } from "./dateFormat"; import { getDefaultMaxDate, getDefaultMinDate, IDatePickerBaseProps } from "./datePickerCore"; @@ -410,8 +410,9 @@ export class DateRangeInput extends AbstractPureComponent { + if (this.props.closeOnSelection) { + // trivial case when TimePicker is not shown + if (this.props.timePrecision == null) { + return false; + } + + const fallbackDate = new Date(new Date().setHours(0, 0, 0, 0)); + const [selectedStart, selectedEnd] = this.getSelectedRange([fallbackDate, fallbackDate]); + + // case to check if the user has changed TimePicker values + if ( + areSameTime(selectedStart, nextSelectedStart) === true && + areSameTime(selectedEnd, nextSelectedEnd) === true + ) { + return false; + } + return true; + } + + return true; + }; + private getInitialRange = (props = this.props): DateRange => { const { defaultValue, value } = props; if (value != null) { @@ -746,7 +770,7 @@ export class DateRangeInput extends AbstractPureComponent { + private getSelectedRange = (fallbackRange?: [Date, Date]) => { let selectedStart: Date; let selectedEnd: Date; @@ -763,8 +787,9 @@ export class DateRangeInput extends AbstractPureComponent { - return this.isDateValidAndInRange(selectedBound) ? selectedBound : undefined; + return dateRange.map((selectedBound: Date | undefined, index: number) => { + const fallbackDate = fallbackRange != null ? fallbackRange[index] : undefined; + return this.isDateValidAndInRange(selectedBound) ? selectedBound : fallbackDate; }) as DateRange; }; diff --git a/packages/datetime/test/dateRangeInputTests.tsx b/packages/datetime/test/dateRangeInputTests.tsx index f684081643..e3bf26d0f8 100644 --- a/packages/datetime/test/dateRangeInputTests.tsx +++ b/packages/datetime/test/dateRangeInputTests.tsx @@ -155,16 +155,50 @@ describe("", () => { expect(isEndInputFocused(root), "end input focus to be false").to.be.false; }); - after(() => { + it("when timePrecision != null && closeOnSelection=true && values is changed popover should not close", () => { + const { root, getDayElement } = wrap( + , + testsContainerElement, + ); + + root.setState({ isOpen: true }); + + getDayElement(1).simulate("click"); + getDayElement(10).simulate("click"); + + root.setState({ isOpen: true }); + + keyDownOnInput(DateClasses.TIMEPICKER_HOUR, Keys.ARROW_UP); + root.update(); + expect(root.find(Popover).prop("isOpen")).to.be.true; + }); + + it("when timePrecision != null && closeOnSelection=true && end values is changed directly (without setting the selectedEnd date) - popover should not close", () => { + const { root } = wrap( + , + testsContainerElement, + ); + + root.setState({ isOpen: true }); + keyDownOnInput(DateClasses.TIMEPICKER_HOUR, Keys.ARROW_UP); + root.update(); + keyDownOnInput(DateClasses.TIMEPICKER_HOUR, Keys.ARROW_UP, 1); + root.update(); + expect(root.find(Popover).prop("isOpen")).to.be.true; + }); + + afterEach(() => { ReactDOM.unmountComponentAtNode(testsContainerElement); }); - function keyDownOnInput(className: string, key: number) { - TestUtils.Simulate.keyDown(findTimePickerInputElement(className), { which: key }); + function keyDownOnInput(className: string, key: number, inputElementIndex: number = 0) { + TestUtils.Simulate.keyDown(findTimePickerInputElement(className, inputElementIndex), { which: key }); } - function findTimePickerInputElement(className: string) { - return document.querySelector(`.${DateClasses.TIMEPICKER_INPUT}.${className}`) as HTMLInputElement; + function findTimePickerInputElement(className: string, inputElementIndex: number = 0) { + return document.querySelectorAll(`.${DateClasses.TIMEPICKER_INPUT}.${className}`)[ + inputElementIndex + ] as HTMLInputElement; } }); @@ -335,6 +369,16 @@ describe("", () => { getDayElement(10).simulate("click"); expect(root.state("isOpen")).to.be.false; }); + + it("if closeOnSelection=true && timePrecision != null, popover closes when full date range is selected", () => { + const { root, getDayElement } = wrap( + , + ); + root.setState({ isOpen: true }); + getDayElement(1).simulate("click"); + getDayElement(10).simulate("click"); + expect(root.state("isOpen")).to.be.false; + }); }); it("accepts contiguousCalendarMonths prop and passes it to the date range picker", () => {