UNPKG

38.9 kBJavaScriptView Raw
1"use strict";
2/*
3 * Copyright 2017 Palantir Technologies, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17Object.defineProperty(exports, "__esModule", { value: true });
18exports.DateRangeInput = void 0;
19var tslib_1 = require("tslib");
20/**
21 * @fileoverview This component is DEPRECATED, and the code is frozen.
22 * All changes & bugfixes should be made to DateRangeInput2 in the datetime2
23 * package instead.
24 */
25/* eslint-disable deprecation/deprecation, @blueprintjs/no-deprecated-components */
26var classnames_1 = tslib_1.__importDefault(require("classnames"));
27var React = tslib_1.__importStar(require("react"));
28var react_day_picker_1 = tslib_1.__importDefault(require("react-day-picker"));
29var core_1 = require("@blueprintjs/core");
30var dateUtils_1 = require("./common/dateUtils");
31var Errors = tslib_1.__importStar(require("./common/errors"));
32var dateFormat_1 = require("./dateFormat");
33var datePickerCore_1 = require("./datePickerCore");
34var dateRangePicker_1 = require("./dateRangePicker");
35/**
36 * Date range input component.
37 *
38 * @see https://blueprintjs.com/docs/#datetime/daterangeinput
39 * @deprecated use { DateRangeInput2 } from "@blueprintjs/datetime2"
40 */
41var DateRangeInput = /** @class */ (function (_super) {
42 tslib_1.__extends(DateRangeInput, _super);
43 function DateRangeInput(props) {
44 var _this = this;
45 var _a, _b;
46 _this = _super.call(this, props) || this;
47 _this.startInputElement = null;
48 _this.endInputElement = null;
49 _this.handleStartInputRef = (0, core_1.refHandler)(_this, "startInputElement", (_a = _this.props.startInputProps) === null || _a === void 0 ? void 0 : _a.inputRef);
50 _this.handleEndInputRef = (0, core_1.refHandler)(_this, "endInputElement", (_b = _this.props.endInputProps) === null || _b === void 0 ? void 0 : _b.inputRef);
51 _this.renderInputGroup = function (boundary) {
52 var inputProps = _this.getInputProps(boundary);
53 var handleInputEvent = boundary === core_1.Boundary.START ? _this.handleStartInputEvent : _this.handleEndInputEvent;
54 return (React.createElement(core_1.InputGroup, tslib_1.__assign({ autoComplete: "off", disabled: inputProps.disabled || _this.props.disabled }, inputProps, { intent: _this.isInputInErrorState(boundary) ? core_1.Intent.DANGER : inputProps.intent, inputRef: _this.getInputRef(boundary), onBlur: handleInputEvent, onChange: handleInputEvent, onClick: handleInputEvent, onFocus: handleInputEvent, onKeyDown: handleInputEvent, onMouseDown: handleInputEvent, placeholder: _this.getInputPlaceholderString(boundary), value: _this.getInputDisplayString(boundary) })));
55 };
56 // Callbacks - DateRangePicker
57 // ===========================
58 _this.handleDateRangePickerChange = function (selectedRange, didSubmitWithEnter) {
59 var _a, _b;
60 if (didSubmitWithEnter === void 0) { didSubmitWithEnter = false; }
61 // ignore mouse events in the date-range picker if the popover is animating closed.
62 if (!_this.state.isOpen) {
63 return;
64 }
65 var selectedStart = selectedRange[0], selectedEnd = selectedRange[1];
66 var isOpen = true;
67 var isStartInputFocused;
68 var isEndInputFocused;
69 var startHoverString;
70 var endHoverString;
71 var boundaryToModify;
72 if (selectedStart == null) {
73 // focus the start field by default or if only an end date is specified
74 if (_this.props.timePrecision == null) {
75 isStartInputFocused = true;
76 isEndInputFocused = false;
77 }
78 else {
79 isStartInputFocused = false;
80 isEndInputFocused = false;
81 boundaryToModify = core_1.Boundary.START;
82 }
83 // for clarity, hide the hover string until the mouse moves over a different date
84 startHoverString = null;
85 }
86 else if (selectedEnd == null) {
87 // focus the end field if a start date is specified
88 if (_this.props.timePrecision == null) {
89 isStartInputFocused = false;
90 isEndInputFocused = true;
91 }
92 else {
93 isStartInputFocused = false;
94 isEndInputFocused = false;
95 boundaryToModify = core_1.Boundary.END;
96 }
97 endHoverString = null;
98 }
99 else if (_this.props.closeOnSelection) {
100 isOpen = _this.getIsOpenValueWhenDateChanges(selectedStart, selectedEnd);
101 isStartInputFocused = false;
102 if (_this.props.timePrecision == null && didSubmitWithEnter) {
103 // if we submit via click or Tab, the focus will have moved already.
104 // it we submit with Enter, the focus won't have moved, and setting
105 // the flag to false won't have an effect anyway, so leave it true.
106 isEndInputFocused = true;
107 }
108 else {
109 isEndInputFocused = false;
110 boundaryToModify = core_1.Boundary.END;
111 }
112 }
113 else if (_this.state.lastFocusedField === core_1.Boundary.START) {
114 // keep the start field focused
115 if (_this.props.timePrecision == null) {
116 isStartInputFocused = true;
117 isEndInputFocused = false;
118 }
119 else {
120 isStartInputFocused = false;
121 isEndInputFocused = false;
122 boundaryToModify = core_1.Boundary.START;
123 }
124 }
125 else if (_this.props.timePrecision == null) {
126 // keep the end field focused
127 isStartInputFocused = false;
128 isEndInputFocused = true;
129 }
130 else {
131 isStartInputFocused = false;
132 isEndInputFocused = false;
133 boundaryToModify = core_1.Boundary.END;
134 }
135 var baseStateChange = {
136 boundaryToModify: boundaryToModify,
137 endHoverString: endHoverString,
138 endInputString: _this.formatDate(selectedEnd),
139 isEndInputFocused: isEndInputFocused,
140 isOpen: isOpen,
141 isStartInputFocused: isStartInputFocused,
142 startHoverString: startHoverString,
143 startInputString: _this.formatDate(selectedStart),
144 wasLastFocusChangeDueToHover: false,
145 };
146 if (_this.isControlled()) {
147 _this.setState(baseStateChange);
148 }
149 else {
150 _this.setState(tslib_1.__assign(tslib_1.__assign({}, baseStateChange), { selectedEnd: selectedEnd, selectedStart: selectedStart }));
151 }
152 (_b = (_a = _this.props).onChange) === null || _b === void 0 ? void 0 : _b.call(_a, selectedRange);
153 };
154 _this.handleShortcutChange = function (_, selectedShortcutIndex) {
155 _this.setState({ selectedShortcutIndex: selectedShortcutIndex });
156 };
157 _this.handleDateRangePickerHoverChange = function (hoveredRange, _hoveredDay, hoveredBoundary) {
158 // ignore mouse events in the date-range picker if the popover is animating closed.
159 if (!_this.state.isOpen) {
160 return;
161 }
162 if (hoveredRange == null) {
163 // undo whatever focus changes we made while hovering over various calendar dates
164 var isEndInputFocused = _this.state.boundaryToModify === core_1.Boundary.END;
165 _this.setState({
166 endHoverString: null,
167 isEndInputFocused: isEndInputFocused,
168 isStartInputFocused: !isEndInputFocused,
169 lastFocusedField: _this.state.boundaryToModify,
170 startHoverString: null,
171 });
172 }
173 else {
174 var hoveredStart = hoveredRange[0], hoveredEnd = hoveredRange[1];
175 var isStartInputFocused = hoveredBoundary != null ? hoveredBoundary === core_1.Boundary.START : _this.state.isStartInputFocused;
176 var isEndInputFocused = hoveredBoundary != null ? hoveredBoundary === core_1.Boundary.END : _this.state.isEndInputFocused;
177 _this.setState({
178 endHoverString: _this.formatDate(hoveredEnd),
179 isEndInputFocused: isEndInputFocused,
180 isStartInputFocused: isStartInputFocused,
181 lastFocusedField: isStartInputFocused ? core_1.Boundary.START : core_1.Boundary.END,
182 shouldSelectAfterUpdate: _this.props.selectAllOnFocus,
183 startHoverString: _this.formatDate(hoveredStart),
184 wasLastFocusChangeDueToHover: true,
185 });
186 }
187 };
188 // Callbacks - Input
189 // =================
190 // instantiate these two functions once so we don't have to for each callback on each render.
191 _this.handleStartInputEvent = function (e) {
192 _this.handleInputEvent(e, core_1.Boundary.START);
193 };
194 _this.handleEndInputEvent = function (e) {
195 _this.handleInputEvent(e, core_1.Boundary.END);
196 };
197 _this.handleInputEvent = function (e, boundary) {
198 var _a, _b, _c, _d, _f, _g;
199 var inputProps = _this.getInputProps(boundary);
200 switch (e.type) {
201 case "blur":
202 _this.handleInputBlur(e, boundary);
203 (_a = inputProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(inputProps, e);
204 break;
205 case "change":
206 _this.handleInputChange(e, boundary);
207 (_b = inputProps.onChange) === null || _b === void 0 ? void 0 : _b.call(inputProps, e);
208 break;
209 case "click":
210 e = e;
211 _this.handleInputClick(e);
212 (_c = inputProps.onClick) === null || _c === void 0 ? void 0 : _c.call(inputProps, e);
213 break;
214 case "focus":
215 _this.handleInputFocus(e, boundary);
216 (_d = inputProps.onFocus) === null || _d === void 0 ? void 0 : _d.call(inputProps, e);
217 break;
218 case "keydown":
219 e = e;
220 _this.handleInputKeyDown(e);
221 (_f = inputProps.onKeyDown) === null || _f === void 0 ? void 0 : _f.call(inputProps, e);
222 break;
223 case "mousedown":
224 e = e;
225 _this.handleInputMouseDown();
226 (_g = inputProps.onMouseDown) === null || _g === void 0 ? void 0 : _g.call(inputProps, e);
227 break;
228 default:
229 break;
230 }
231 };
232 // add a keydown listener to persistently change focus when tabbing:
233 // - if focused in start field, Tab moves focus to end field
234 // - if focused in end field, Shift+Tab moves focus to start field
235 _this.handleInputKeyDown = function (e) {
236 // HACKHACK: https://github.com/palantir/blueprint/issues/4165
237 var isTabPressed = e.which === core_1.Keys.TAB;
238 var isEnterPressed = e.which === core_1.Keys.ENTER;
239 var isShiftPressed = e.shiftKey;
240 var _a = _this.state, selectedStart = _a.selectedStart, selectedEnd = _a.selectedEnd;
241 // order of JS events is our enemy here. when tabbing between fields,
242 // this handler will fire in the middle of a focus exchange when no
243 // field is currently focused. we work around this by referring to the
244 // most recently focused field, rather than the currently focused field.
245 var wasStartFieldFocused = _this.state.lastFocusedField === core_1.Boundary.START;
246 var wasEndFieldFocused = _this.state.lastFocusedField === core_1.Boundary.END;
247 // move focus to the other field
248 if (isTabPressed) {
249 var isEndInputFocused = void 0;
250 var isStartInputFocused = void 0;
251 var isOpen = true;
252 if (wasStartFieldFocused && !isShiftPressed) {
253 isStartInputFocused = false;
254 isEndInputFocused = true;
255 // prevent the default focus-change behavior to avoid race conditions;
256 // we'll handle the focus change ourselves in componentDidUpdate.
257 e.preventDefault();
258 }
259 else if (wasEndFieldFocused && isShiftPressed) {
260 isStartInputFocused = true;
261 isEndInputFocused = false;
262 e.preventDefault();
263 }
264 else {
265 // don't prevent default here, otherwise Tab won't do anything.
266 isStartInputFocused = false;
267 isEndInputFocused = false;
268 isOpen = false;
269 }
270 _this.setState({
271 isEndInputFocused: isEndInputFocused,
272 isOpen: isOpen,
273 isStartInputFocused: isStartInputFocused,
274 wasLastFocusChangeDueToHover: false,
275 });
276 }
277 else if (wasStartFieldFocused && isEnterPressed) {
278 var nextStartDate = _this.parseDate(_this.state.startInputString);
279 _this.handleDateRangePickerChange([nextStartDate, selectedEnd], true);
280 }
281 else if (wasEndFieldFocused && isEnterPressed) {
282 var nextEndDate = _this.parseDate(_this.state.endInputString);
283 _this.handleDateRangePickerChange([selectedStart, nextEndDate], true);
284 }
285 else {
286 // let the default keystroke happen without side effects
287 return;
288 }
289 };
290 _this.handleInputMouseDown = function () {
291 // clicking in the field constitutes an explicit focus change. we update
292 // the flag on "mousedown" instead of on "click", because it needs to be
293 // set before onFocus is called ("click" triggers after "focus").
294 _this.setState({ wasLastFocusChangeDueToHover: false });
295 };
296 _this.handleInputClick = function (e) {
297 // unless we stop propagation on this event, a click within an input
298 // will close the popover almost as soon as it opens.
299 e.stopPropagation();
300 };
301 _this.handleInputFocus = function (_e, boundary) {
302 var _a;
303 var _b = _this.getStateKeysAndValuesForBoundary(boundary), keys = _b.keys, values = _b.values;
304 var inputString = (0, dateFormat_1.getFormattedDateString)(values.selectedValue, _this.props, true);
305 // change the boundary only if the user explicitly focused in the field.
306 // focus changes from hovering don't count; they're just temporary.
307 var boundaryToModify = _this.state.wasLastFocusChangeDueToHover ? _this.state.boundaryToModify : boundary;
308 _this.setState((_a = {},
309 _a[keys.inputString] = inputString,
310 _a[keys.isInputFocused] = true,
311 _a.boundaryToModify = boundaryToModify,
312 _a.isOpen = true,
313 _a.lastFocusedField = boundary,
314 _a.shouldSelectAfterUpdate = _this.props.selectAllOnFocus,
315 _a.wasLastFocusChangeDueToHover = false,
316 _a));
317 };
318 _this.handleInputBlur = function (_e, boundary) {
319 var _a, _b, _c, _d;
320 var _f, _g;
321 var _h = _this.getStateKeysAndValuesForBoundary(boundary), keys = _h.keys, values = _h.values;
322 var maybeNextDate = _this.parseDate(values.inputString);
323 var isValueControlled = _this.isControlled();
324 var nextState = (_a = {},
325 _a[keys.isInputFocused] = false,
326 _a.shouldSelectAfterUpdate = false,
327 _a);
328 if (_this.isInputEmpty(values.inputString)) {
329 if (isValueControlled) {
330 nextState = tslib_1.__assign(tslib_1.__assign({}, nextState), (_b = {}, _b[keys.inputString] = (0, dateFormat_1.getFormattedDateString)(values.controlledValue, _this.props), _b));
331 }
332 else {
333 nextState = tslib_1.__assign(tslib_1.__assign({}, nextState), (_c = {}, _c[keys.inputString] = null, _c[keys.selectedValue] = null, _c));
334 }
335 }
336 else if (!_this.isNextDateRangeValid(maybeNextDate, boundary)) {
337 if (!isValueControlled) {
338 nextState = tslib_1.__assign(tslib_1.__assign({}, nextState), (_d = {}, _d[keys.inputString] = null, _d[keys.selectedValue] = maybeNextDate, _d));
339 }
340 (_g = (_f = _this.props).onError) === null || _g === void 0 ? void 0 : _g.call(_f, _this.getDateRangeForCallback(maybeNextDate, boundary));
341 }
342 _this.setState(nextState);
343 };
344 _this.handleInputChange = function (e, boundary) {
345 var _a, _b, _c, _d, _f;
346 var _g, _h, _j, _k;
347 var inputString = e.target.value;
348 var keys = _this.getStateKeysAndValuesForBoundary(boundary).keys;
349 var maybeNextDate = _this.parseDate(inputString);
350 var isValueControlled = _this.isControlled();
351 var nextState = { shouldSelectAfterUpdate: false };
352 if (inputString.length === 0) {
353 // this case will be relevant when we start showing the hovered range in the input
354 // fields. goal is to show an empty field for clarity until the mouse moves over a
355 // different date.
356 var baseState = tslib_1.__assign(tslib_1.__assign({}, nextState), (_a = {}, _a[keys.inputString] = "", _a));
357 if (isValueControlled) {
358 nextState = baseState;
359 }
360 else {
361 nextState = tslib_1.__assign(tslib_1.__assign({}, baseState), (_b = {}, _b[keys.selectedValue] = null, _b));
362 }
363 (_h = (_g = _this.props).onChange) === null || _h === void 0 ? void 0 : _h.call(_g, _this.getDateRangeForCallback(null, boundary));
364 }
365 else if (_this.isDateValidAndInRange(maybeNextDate)) {
366 // note that error cases that depend on both fields (e.g. overlapping dates) should fall
367 // through into this block so that the UI can update immediately, possibly with an error
368 // message on the other field.
369 // also, clear the hover string to ensure the most recent keystroke appears.
370 var baseState = tslib_1.__assign(tslib_1.__assign({}, nextState), (_c = {}, _c[keys.hoverString] = null, _c[keys.inputString] = inputString, _c));
371 if (isValueControlled) {
372 nextState = baseState;
373 }
374 else {
375 nextState = tslib_1.__assign(tslib_1.__assign({}, baseState), (_d = {}, _d[keys.selectedValue] = maybeNextDate, _d));
376 }
377 if (_this.isNextDateRangeValid(maybeNextDate, boundary)) {
378 (_k = (_j = _this.props).onChange) === null || _k === void 0 ? void 0 : _k.call(_j, _this.getDateRangeForCallback(maybeNextDate, boundary));
379 }
380 }
381 else {
382 // again, clear the hover string to ensure the most recent keystroke appears
383 nextState = tslib_1.__assign(tslib_1.__assign({}, nextState), (_f = {}, _f[keys.inputString] = inputString, _f[keys.hoverString] = null, _f));
384 }
385 _this.setState(nextState);
386 };
387 // Callbacks - Popover
388 // ===================
389 _this.handlePopoverClose = function (event) {
390 var _a, _b;
391 _this.setState({ isOpen: false });
392 (_b = (_a = _this.props.popoverProps).onClose) === null || _b === void 0 ? void 0 : _b.call(_a, event);
393 };
394 _this.getIsOpenValueWhenDateChanges = function (nextSelectedStart, nextSelectedEnd) {
395 if (_this.props.closeOnSelection) {
396 // trivial case when TimePicker is not shown
397 if (_this.props.timePrecision == null) {
398 return false;
399 }
400 var fallbackDate = new Date(new Date().setHours(0, 0, 0, 0));
401 var _a = _this.getSelectedRange([fallbackDate, fallbackDate]), selectedStart = _a[0], selectedEnd = _a[1];
402 // case to check if the user has changed TimePicker values
403 if ((0, dateUtils_1.areSameTime)(selectedStart, nextSelectedStart) === true &&
404 (0, dateUtils_1.areSameTime)(selectedEnd, nextSelectedEnd) === true) {
405 return false;
406 }
407 return true;
408 }
409 return true;
410 };
411 _this.getInitialRange = function (props) {
412 if (props === void 0) { props = _this.props; }
413 var defaultValue = props.defaultValue, value = props.value;
414 if (value != null) {
415 return value;
416 }
417 else if (defaultValue != null) {
418 return defaultValue;
419 }
420 else {
421 return [null, null];
422 }
423 };
424 _this.getSelectedRange = function (fallbackRange) {
425 var _a;
426 var selectedStart;
427 var selectedEnd;
428 if (_this.isControlled()) {
429 _a = _this.props.value, selectedStart = _a[0], selectedEnd = _a[1];
430 }
431 else {
432 selectedStart = _this.state.selectedStart;
433 selectedEnd = _this.state.selectedEnd;
434 }
435 // this helper function checks if the provided boundary date *would* overlap the selected
436 // other boundary date. providing the already-selected start date simply tells us if we're
437 // currently in an overlapping state.
438 var doBoundaryDatesOverlap = _this.doBoundaryDatesOverlap(selectedStart, core_1.Boundary.START);
439 var dateRange = [selectedStart, doBoundaryDatesOverlap ? undefined : selectedEnd];
440 return dateRange.map(function (selectedBound, index) {
441 var fallbackDate = fallbackRange != null ? fallbackRange[index] : undefined;
442 return _this.isDateValidAndInRange(selectedBound) ? selectedBound : fallbackDate;
443 });
444 };
445 _this.getInputDisplayString = function (boundary) {
446 var values = _this.getStateKeysAndValuesForBoundary(boundary).values;
447 var isInputFocused = values.isInputFocused, inputString = values.inputString, selectedValue = values.selectedValue, hoverString = values.hoverString;
448 if (hoverString != null) {
449 return hoverString;
450 }
451 else if (isInputFocused) {
452 return inputString == null ? "" : inputString;
453 }
454 else if (selectedValue == null) {
455 return "";
456 }
457 else if (_this.doesEndBoundaryOverlapStartBoundary(selectedValue, boundary)) {
458 return _this.props.overlappingDatesMessage;
459 }
460 else {
461 return (0, dateFormat_1.getFormattedDateString)(selectedValue, _this.props);
462 }
463 };
464 _this.getInputPlaceholderString = function (boundary) {
465 var isStartBoundary = boundary === core_1.Boundary.START;
466 var isEndBoundary = boundary === core_1.Boundary.END;
467 var inputProps = _this.getInputProps(boundary);
468 var isInputFocused = _this.getStateKeysAndValuesForBoundary(boundary).values.isInputFocused;
469 // use the custom placeholder text for the input, if providied
470 if (inputProps.placeholder != null) {
471 return inputProps.placeholder;
472 }
473 else if (isStartBoundary) {
474 return isInputFocused ? _this.state.formattedMinDateString : "Start date";
475 }
476 else if (isEndBoundary) {
477 return isInputFocused ? _this.state.formattedMaxDateString : "End date";
478 }
479 else {
480 return "";
481 }
482 };
483 _this.getInputProps = function (boundary) {
484 return boundary === core_1.Boundary.START ? _this.props.startInputProps : _this.props.endInputProps;
485 };
486 _this.getInputRef = function (boundary) {
487 return boundary === core_1.Boundary.START ? _this.handleStartInputRef : _this.handleEndInputRef;
488 };
489 _this.getStateKeysAndValuesForBoundary = function (boundary) {
490 var controlledRange = _this.props.value;
491 if (boundary === core_1.Boundary.START) {
492 return {
493 keys: {
494 hoverString: "startHoverString",
495 inputString: "startInputString",
496 isInputFocused: "isStartInputFocused",
497 selectedValue: "selectedStart",
498 },
499 values: {
500 controlledValue: controlledRange != null ? controlledRange[0] : undefined,
501 hoverString: _this.state.startHoverString,
502 inputString: _this.state.startInputString,
503 isInputFocused: _this.state.isStartInputFocused,
504 selectedValue: _this.state.selectedStart,
505 },
506 };
507 }
508 else {
509 return {
510 keys: {
511 hoverString: "endHoverString",
512 inputString: "endInputString",
513 isInputFocused: "isEndInputFocused",
514 selectedValue: "selectedEnd",
515 },
516 values: {
517 controlledValue: controlledRange != null ? controlledRange[1] : undefined,
518 hoverString: _this.state.endHoverString,
519 inputString: _this.state.endInputString,
520 isInputFocused: _this.state.isEndInputFocused,
521 selectedValue: _this.state.selectedEnd,
522 },
523 };
524 }
525 };
526 _this.getDateRangeForCallback = function (currDate, currBoundary) {
527 var otherBoundary = _this.getOtherBoundary(currBoundary);
528 var otherDate = _this.getStateKeysAndValuesForBoundary(otherBoundary).values.selectedValue;
529 return currBoundary === core_1.Boundary.START ? [currDate, otherDate] : [otherDate, currDate];
530 };
531 _this.getOtherBoundary = function (boundary) {
532 return boundary === core_1.Boundary.START ? core_1.Boundary.END : core_1.Boundary.START;
533 };
534 _this.doBoundaryDatesOverlap = function (date, boundary) {
535 var allowSingleDayRange = _this.props.allowSingleDayRange;
536 var otherBoundary = _this.getOtherBoundary(boundary);
537 var otherBoundaryDate = _this.getStateKeysAndValuesForBoundary(otherBoundary).values.selectedValue;
538 if (date == null || otherBoundaryDate == null) {
539 return false;
540 }
541 if (boundary === core_1.Boundary.START) {
542 var isAfter = date > otherBoundaryDate;
543 return isAfter || (!allowSingleDayRange && react_day_picker_1.default.DateUtils.isSameDay(date, otherBoundaryDate));
544 }
545 else {
546 var isBefore = date < otherBoundaryDate;
547 return isBefore || (!allowSingleDayRange && react_day_picker_1.default.DateUtils.isSameDay(date, otherBoundaryDate));
548 }
549 };
550 /**
551 * Returns true if the provided boundary is an END boundary overlapping the
552 * selected start date. (If the boundaries overlap, we consider the END
553 * boundary to be erroneous.)
554 */
555 _this.doesEndBoundaryOverlapStartBoundary = function (boundaryDate, boundary) {
556 return boundary === core_1.Boundary.START ? false : _this.doBoundaryDatesOverlap(boundaryDate, boundary);
557 };
558 _this.isControlled = function () { return _this.props.value !== undefined; };
559 _this.isInputEmpty = function (inputString) { return inputString == null || inputString.length === 0; };
560 _this.isInputInErrorState = function (boundary) {
561 var values = _this.getStateKeysAndValuesForBoundary(boundary).values;
562 var isInputFocused = values.isInputFocused, hoverString = values.hoverString, inputString = values.inputString, selectedValue = values.selectedValue;
563 if (hoverString != null || _this.isInputEmpty(inputString)) {
564 // don't show an error state while we're hovering over a valid date.
565 return false;
566 }
567 var boundaryValue = isInputFocused ? _this.parseDate(inputString) : selectedValue;
568 return (boundaryValue != null &&
569 (!_this.isDateValidAndInRange(boundaryValue) ||
570 _this.doesEndBoundaryOverlapStartBoundary(boundaryValue, boundary)));
571 };
572 _this.isDateValidAndInRange = function (date) {
573 return (0, dateUtils_1.isDateValid)(date) && (0, dateUtils_1.isDayInRange)(date, [_this.props.minDate, _this.props.maxDate]);
574 };
575 _this.reset(props);
576 return _this;
577 }
578 /**
579 * Public method intended for unit testing only. Do not use in feature work!
580 */
581 DateRangeInput.prototype.reset = function (props) {
582 if (props === void 0) { props = this.props; }
583 var _a = this.getInitialRange(), selectedStart = _a[0], selectedEnd = _a[1];
584 this.state = {
585 formattedMaxDateString: this.getFormattedMinMaxDateString(props, "maxDate"),
586 formattedMinDateString: this.getFormattedMinMaxDateString(props, "minDate"),
587 isOpen: false,
588 selectedEnd: selectedEnd,
589 selectedShortcutIndex: -1,
590 selectedStart: selectedStart,
591 };
592 };
593 DateRangeInput.prototype.componentDidUpdate = function (prevProps, prevState) {
594 var _a, _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
595 _super.prototype.componentDidUpdate.call(this, prevProps, prevState);
596 var _r = this.state, isStartInputFocused = _r.isStartInputFocused, isEndInputFocused = _r.isEndInputFocused, shouldSelectAfterUpdate = _r.shouldSelectAfterUpdate;
597 if (((_a = prevProps.startInputProps) === null || _a === void 0 ? void 0 : _a.inputRef) !== ((_b = this.props.startInputProps) === null || _b === void 0 ? void 0 : _b.inputRef)) {
598 (0, core_1.setRef)((_c = prevProps.startInputProps) === null || _c === void 0 ? void 0 : _c.inputRef, null);
599 this.handleStartInputRef = (0, core_1.refHandler)(this, "startInputElement", (_d = this.props.startInputProps) === null || _d === void 0 ? void 0 : _d.inputRef);
600 (0, core_1.setRef)((_f = this.props.startInputProps) === null || _f === void 0 ? void 0 : _f.inputRef, this.startInputElement);
601 }
602 if (((_g = prevProps.endInputProps) === null || _g === void 0 ? void 0 : _g.inputRef) !== ((_h = this.props.endInputProps) === null || _h === void 0 ? void 0 : _h.inputRef)) {
603 (0, core_1.setRef)((_j = prevProps.endInputProps) === null || _j === void 0 ? void 0 : _j.inputRef, null);
604 this.handleEndInputRef = (0, core_1.refHandler)(this, "endInputElement", (_k = this.props.endInputProps) === null || _k === void 0 ? void 0 : _k.inputRef);
605 (0, core_1.setRef)((_l = this.props.endInputProps) === null || _l === void 0 ? void 0 : _l.inputRef, this.endInputElement);
606 }
607 var shouldFocusStartInput = this.shouldFocusInputRef(isStartInputFocused, this.startInputElement);
608 var shouldFocusEndInput = this.shouldFocusInputRef(isEndInputFocused, this.endInputElement);
609 if (shouldFocusStartInput) {
610 (_m = this.startInputElement) === null || _m === void 0 ? void 0 : _m.focus();
611 }
612 else if (shouldFocusEndInput) {
613 (_o = this.endInputElement) === null || _o === void 0 ? void 0 : _o.focus();
614 }
615 if (isStartInputFocused && shouldSelectAfterUpdate) {
616 (_p = this.startInputElement) === null || _p === void 0 ? void 0 : _p.select();
617 }
618 else if (isEndInputFocused && shouldSelectAfterUpdate) {
619 (_q = this.endInputElement) === null || _q === void 0 ? void 0 : _q.select();
620 }
621 var nextState = {};
622 if (this.props.value !== prevProps.value) {
623 var _s = this.getInitialRange(this.props), selectedStart = _s[0], selectedEnd = _s[1];
624 nextState = tslib_1.__assign(tslib_1.__assign({}, nextState), { selectedStart: selectedStart, selectedEnd: selectedEnd });
625 }
626 // cache the formatted date strings to avoid computing on each render.
627 if (this.props.minDate !== prevProps.minDate) {
628 var formattedMinDateString = this.getFormattedMinMaxDateString(this.props, "minDate");
629 nextState = tslib_1.__assign(tslib_1.__assign({}, nextState), { formattedMinDateString: formattedMinDateString });
630 }
631 if (this.props.maxDate !== prevProps.maxDate) {
632 var formattedMaxDateString = this.getFormattedMinMaxDateString(this.props, "maxDate");
633 nextState = tslib_1.__assign(tslib_1.__assign({}, nextState), { formattedMaxDateString: formattedMaxDateString });
634 }
635 this.setState(nextState);
636 };
637 DateRangeInput.prototype.render = function () {
638 var selectedShortcutIndex = this.state.selectedShortcutIndex;
639 var _a = this.props.popoverProps, popoverProps = _a === void 0 ? {} : _a;
640 var popoverContent = (React.createElement(dateRangePicker_1.DateRangePicker, tslib_1.__assign({}, this.props, { selectedShortcutIndex: selectedShortcutIndex, boundaryToModify: this.state.boundaryToModify, onChange: this.handleDateRangePickerChange, onShortcutChange: this.handleShortcutChange, onHoverChange: this.handleDateRangePickerHoverChange, value: this.getSelectedRange() })));
641 var popoverClassName = (0, classnames_1.default)(popoverProps.className, this.props.className);
642 // allow custom props for the popover and each input group, but pass them in an order that
643 // guarantees only some props are overridable.
644 return (React.createElement(core_1.Popover, tslib_1.__assign({ isOpen: this.state.isOpen, position: core_1.Position.BOTTOM_LEFT }, this.props.popoverProps, { autoFocus: false, className: popoverClassName, content: popoverContent, enforceFocus: false, onClose: this.handlePopoverClose }),
645 React.createElement("div", { className: core_1.Classes.CONTROL_GROUP },
646 this.renderInputGroup(core_1.Boundary.START),
647 this.renderInputGroup(core_1.Boundary.END))));
648 };
649 DateRangeInput.prototype.validateProps = function (props) {
650 if (props.value === null) {
651 throw new Error(Errors.DATERANGEINPUT_NULL_VALUE);
652 }
653 };
654 // Helpers
655 // =======
656 DateRangeInput.prototype.shouldFocusInputRef = function (isFocused, inputRef) {
657 return isFocused && inputRef !== undefined && document.activeElement !== inputRef;
658 };
659 DateRangeInput.prototype.isNextDateRangeValid = function (nextDate, boundary) {
660 return this.isDateValidAndInRange(nextDate) && !this.doBoundaryDatesOverlap(nextDate, boundary);
661 };
662 // this is a slightly kludgy function, but it saves us a good amount of repeated code between
663 // the constructor and componentDidUpdate.
664 DateRangeInput.prototype.getFormattedMinMaxDateString = function (props, propName) {
665 var date = props[propName];
666 var defaultDate = DateRangeInput.defaultProps[propName];
667 // default values are applied only if a prop is strictly `undefined`
668 // See: https://facebook.github.io/react/docs/react-component.html#defaultprops
669 return (0, dateFormat_1.getFormattedDateString)(date === undefined ? defaultDate : date, this.props);
670 };
671 DateRangeInput.prototype.parseDate = function (dateString) {
672 if (dateString === this.props.outOfRangeMessage || dateString === this.props.invalidDateMessage) {
673 return null;
674 }
675 var _a = this.props, locale = _a.locale, parseDate = _a.parseDate;
676 var newDate = parseDate(dateString, locale);
677 return newDate === false ? new Date(undefined) : newDate;
678 };
679 DateRangeInput.prototype.formatDate = function (date) {
680 if (!this.isDateValidAndInRange(date)) {
681 return "";
682 }
683 var _a = this.props, locale = _a.locale, formatDate = _a.formatDate;
684 return formatDate(date, locale);
685 };
686 DateRangeInput.defaultProps = {
687 allowSingleDayRange: false,
688 closeOnSelection: true,
689 contiguousCalendarMonths: true,
690 dayPickerProps: {},
691 disabled: false,
692 endInputProps: {},
693 invalidDateMessage: "Invalid date",
694 maxDate: (0, datePickerCore_1.getDefaultMaxDate)(),
695 minDate: (0, datePickerCore_1.getDefaultMinDate)(),
696 outOfRangeMessage: "Out of range",
697 overlappingDatesMessage: "Overlapping dates",
698 popoverProps: {},
699 selectAllOnFocus: false,
700 shortcuts: true,
701 singleMonthOnly: false,
702 startInputProps: {},
703 };
704 DateRangeInput.displayName = "".concat(core_1.DISPLAYNAME_PREFIX, ".DateRangeInput");
705 return DateRangeInput;
706}(core_1.AbstractPureComponent2));
707exports.DateRangeInput = DateRangeInput;
708//# sourceMappingURL=dateRangeInput.js.map
\No newline at end of file