UNPKG

16.6 kBJavaScriptView Raw
1/*
2 * Copyright 2016 Palantir Technologies, Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16import { __assign, __extends } from "tslib";
17/**
18 * @fileoverview This component is DEPRECATED, and the code is frozen.
19 * All changes & bugfixes should be made to DateInput2 in the datetime2
20 * package instead.
21 */
22/* eslint-disable deprecation/deprecation, @blueprintjs/no-deprecated-components */
23import classNames from "classnames";
24import * as React from "react";
25import { AbstractPureComponent2, DISPLAYNAME_PREFIX, InputGroup, Intent, Keys, Popover, refHandler, setRef, } from "@blueprintjs/core";
26import * as Classes from "./common/classes";
27import { isDateValid, isDayInRange } from "./common/dateUtils";
28import { getFormattedDateString } from "./dateFormat";
29import { DatePicker } from "./datePicker";
30import { getDefaultMaxDate, getDefaultMinDate } from "./datePickerCore";
31/**
32 * Date input component.
33 *
34 * @see https://blueprintjs.com/docs/#datetime/dateinput
35 * @deprecated use { DateInput2 } from "@blueprintjs/datetime2"
36 */
37var DateInput = /** @class */ (function (_super) {
38 __extends(DateInput, _super);
39 function DateInput() {
40 var _this = this;
41 var _a;
42 _this = _super.apply(this, arguments) || this;
43 _this.state = {
44 isInputFocused: false,
45 isOpen: false,
46 value: _this.props.value !== undefined ? _this.props.value : _this.props.defaultValue,
47 valueString: null,
48 };
49 _this.inputElement = null;
50 _this.popoverContentElement = null;
51 _this.handleInputRef = refHandler(_this, "inputElement", (_a = _this.props.inputProps) === null || _a === void 0 ? void 0 : _a.inputRef);
52 _this.handlePopoverContentRef = refHandler(_this, "popoverContentElement");
53 _this.handleClosePopover = function (e) {
54 var _a;
55 var _b = _this.props.popoverProps, popoverProps = _b === void 0 ? {} : _b;
56 (_a = popoverProps.onClose) === null || _a === void 0 ? void 0 : _a.call(popoverProps, e);
57 _this.setState({ isOpen: false });
58 };
59 _this.handleDateChange = function (newDate, isUserChange, didSubmitWithEnter) {
60 var _a, _b;
61 if (didSubmitWithEnter === void 0) { didSubmitWithEnter = false; }
62 var prevDate = _this.state.value;
63 // this change handler was triggered by a change in month, day, or (if
64 // enabled) time. for UX purposes, we want to close the popover only if
65 // the user explicitly clicked a day within the current month.
66 var isOpen = !isUserChange ||
67 !_this.props.closeOnSelection ||
68 (prevDate != null && (_this.hasMonthChanged(prevDate, newDate) || _this.hasTimeChanged(prevDate, newDate)));
69 // if selecting a date via click or Tab, the input will already be
70 // blurred by now, so sync isInputFocused to false. if selecting via
71 // Enter, setting isInputFocused to false won't do anything by itself,
72 // plus we want the field to retain focus anyway.
73 // (note: spelling out the ternary explicitly reads more clearly.)
74 var isInputFocused = didSubmitWithEnter ? true : false;
75 if (_this.props.value === undefined) {
76 var valueString = getFormattedDateString(newDate, _this.props);
77 _this.setState({ isInputFocused: isInputFocused, isOpen: isOpen, value: newDate, valueString: valueString });
78 }
79 else {
80 _this.setState({ isInputFocused: isInputFocused, isOpen: isOpen });
81 }
82 (_b = (_a = _this.props).onChange) === null || _b === void 0 ? void 0 : _b.call(_a, newDate, isUserChange);
83 };
84 _this.handleInputFocus = function (e) {
85 var valueString = _this.state.value == null ? "" : _this.formatDate(_this.state.value);
86 _this.setState({ isInputFocused: true, isOpen: true, valueString: valueString });
87 _this.safeInvokeInputProp("onFocus", e);
88 };
89 _this.handleInputClick = function (e) {
90 // stop propagation to the Popover's internal handleTargetClick handler;
91 // otherwise, the popover will flicker closed as soon as it opens.
92 e.stopPropagation();
93 _this.safeInvokeInputProp("onClick", e);
94 };
95 _this.handleInputChange = function (e) {
96 var _a, _b, _c, _d;
97 var valueString = e.target.value;
98 var value = _this.parseDate(valueString);
99 if (isDateValid(value) && _this.isDateInRange(value)) {
100 if (_this.props.value === undefined) {
101 _this.setState({ value: value, valueString: valueString });
102 }
103 else {
104 _this.setState({ valueString: valueString });
105 }
106 (_b = (_a = _this.props).onChange) === null || _b === void 0 ? void 0 : _b.call(_a, value, true);
107 }
108 else {
109 if (valueString.length === 0) {
110 (_d = (_c = _this.props).onChange) === null || _d === void 0 ? void 0 : _d.call(_c, null, true);
111 }
112 _this.setState({ valueString: valueString });
113 }
114 _this.safeInvokeInputProp("onChange", e);
115 };
116 _this.handleInputBlur = function (e) {
117 var _a, _b, _c, _d, _e, _f;
118 var valueString = _this.state.valueString;
119 var date = _this.parseDate(valueString);
120 if (valueString.length > 0 &&
121 valueString !== getFormattedDateString(_this.state.value, _this.props) &&
122 (!isDateValid(date) || !_this.isDateInRange(date))) {
123 if (_this.props.value === undefined) {
124 _this.setState({ isInputFocused: false, value: date, valueString: null });
125 }
126 else {
127 _this.setState({ isInputFocused: false });
128 }
129 if (isNaN(date.valueOf())) {
130 (_b = (_a = _this.props).onError) === null || _b === void 0 ? void 0 : _b.call(_a, new Date(undefined));
131 }
132 else if (!_this.isDateInRange(date)) {
133 (_d = (_c = _this.props).onError) === null || _d === void 0 ? void 0 : _d.call(_c, date);
134 }
135 else {
136 (_f = (_e = _this.props).onChange) === null || _f === void 0 ? void 0 : _f.call(_e, date, true);
137 }
138 }
139 else {
140 if (valueString.length === 0) {
141 _this.setState({ isInputFocused: false, value: null, valueString: null });
142 }
143 else {
144 _this.setState({ isInputFocused: false });
145 }
146 }
147 _this.safeInvokeInputProp("onBlur", e);
148 };
149 _this.handleInputKeyDown = function (e) {
150 var _a, _b;
151 // HACKHACK: https://github.com/palantir/blueprint/issues/4165
152 if (e.which === Keys.ENTER) {
153 var nextDate = _this.parseDate(_this.state.valueString);
154 _this.handleDateChange(nextDate, true, true);
155 }
156 else if (e.which === Keys.TAB && e.shiftKey) {
157 // close popover on SHIFT+TAB key press
158 _this.handleClosePopover();
159 }
160 else if (e.which === Keys.TAB && _this.state.isOpen) {
161 (_a = _this.getKeyboardFocusableElements().shift()) === null || _a === void 0 ? void 0 : _a.focus();
162 // necessary to prevent focusing the second focusable element
163 e.preventDefault();
164 }
165 else if (e.which === Keys.ESCAPE) {
166 _this.setState({ isOpen: false });
167 (_b = _this.inputElement) === null || _b === void 0 ? void 0 : _b.blur();
168 }
169 _this.safeInvokeInputProp("onKeyDown", e);
170 };
171 _this.getKeyboardFocusableElements = function () {
172 var _a;
173 var elements = Array.from((_a = _this.popoverContentElement) === null || _a === void 0 ? void 0 : _a.querySelectorAll("button:not([disabled]),input,[tabindex]:not([tabindex='-1'])"));
174 // Remove focus boundary div elements
175 elements.pop();
176 elements.shift();
177 return elements;
178 };
179 _this.handleStartFocusBoundaryFocusIn = function (e) {
180 var _a, _b;
181 if (_this.popoverContentElement.contains(_this.getRelatedTarget(e))) {
182 // Not closing Popover to allow user to freely switch between manually entering a date
183 // string in the input and selecting one via the Popover
184 (_a = _this.inputElement) === null || _a === void 0 ? void 0 : _a.focus();
185 }
186 else {
187 (_b = _this.getKeyboardFocusableElements().shift()) === null || _b === void 0 ? void 0 : _b.focus();
188 }
189 };
190 _this.handleEndFocusBoundaryFocusIn = function (e) {
191 var _a, _b;
192 if (_this.popoverContentElement.contains(_this.getRelatedTarget(e))) {
193 (_a = _this.inputElement) === null || _a === void 0 ? void 0 : _a.focus();
194 _this.handleClosePopover();
195 }
196 else {
197 (_b = _this.getKeyboardFocusableElements().pop()) === null || _b === void 0 ? void 0 : _b.focus();
198 }
199 };
200 _this.handleShortcutChange = function (_, selectedShortcutIndex) {
201 _this.setState({ selectedShortcutIndex: selectedShortcutIndex });
202 };
203 return _this;
204 }
205 DateInput.prototype.render = function () {
206 var _this = this;
207 var _a = this.state, value = _a.value, valueString = _a.valueString;
208 var dateString = this.state.isInputFocused ? valueString : getFormattedDateString(value, this.props);
209 var dateValue = isDateValid(value) ? value : null;
210 var dayPickerProps = __assign(__assign({}, this.props.dayPickerProps), { onDayKeyDown: function (day, modifiers, e) {
211 var _a, _b;
212 (_b = (_a = _this.props.dayPickerProps).onDayKeyDown) === null || _b === void 0 ? void 0 : _b.call(_a, day, modifiers, e);
213 }, onMonthChange: function (month) {
214 var _a, _b;
215 (_b = (_a = _this.props.dayPickerProps).onMonthChange) === null || _b === void 0 ? void 0 : _b.call(_a, month);
216 } });
217 // React's onFocus prop listens to the focusin browser event under the hood, so it's safe to
218 // provide it the focusIn event handlers instead of using a ref and manually adding the
219 // event listeners ourselves.
220 var wrappedPopoverContent = (React.createElement("div", { ref: this.handlePopoverContentRef },
221 React.createElement("div", { onFocus: this.handleStartFocusBoundaryFocusIn, tabIndex: 0 }),
222 React.createElement(DatePicker, __assign({}, this.props, { dayPickerProps: dayPickerProps, onChange: this.handleDateChange, value: dateValue, onShortcutChange: this.handleShortcutChange, selectedShortcutIndex: this.state.selectedShortcutIndex })),
223 React.createElement("div", { onFocus: this.handleEndFocusBoundaryFocusIn, tabIndex: 0 })));
224 // assign default empty object here to prevent mutation
225 var _b = this.props, _c = _b.inputProps, inputProps = _c === void 0 ? {} : _c, _d = _b.popoverProps, popoverProps = _d === void 0 ? {} : _d;
226 var isErrorState = value != null && (!isDateValid(value) || !this.isDateInRange(value));
227 return (React.createElement(Popover, __assign({ isOpen: this.state.isOpen && !this.props.disabled, fill: this.props.fill }, popoverProps, { autoFocus: false, className: classNames(popoverProps.className, this.props.className), content: wrappedPopoverContent, enforceFocus: false, onClose: this.handleClosePopover, popoverClassName: classNames(Classes.DATEINPUT_POPOVER, popoverProps.popoverClassName) }),
228 React.createElement(InputGroup, __assign({ autoComplete: "off", intent: isErrorState ? Intent.DANGER : Intent.NONE, placeholder: this.props.placeholder, rightElement: this.props.rightElement, type: "text" }, inputProps, { disabled: this.props.disabled, inputRef: this.handleInputRef, onBlur: this.handleInputBlur, onChange: this.handleInputChange, onClick: this.handleInputClick, onFocus: this.handleInputFocus, onKeyDown: this.handleInputKeyDown, value: dateString }))));
229 };
230 DateInput.prototype.componentDidUpdate = function (prevProps, prevState) {
231 var _a, _b, _c, _d, _e;
232 _super.prototype.componentDidUpdate.call(this, prevProps, prevState);
233 if (((_a = prevProps.inputProps) === null || _a === void 0 ? void 0 : _a.inputRef) !== ((_b = this.props.inputProps) === null || _b === void 0 ? void 0 : _b.inputRef)) {
234 setRef((_c = prevProps.inputProps) === null || _c === void 0 ? void 0 : _c.inputRef, null);
235 this.handleInputRef = refHandler(this, "inputElement", (_d = this.props.inputProps) === null || _d === void 0 ? void 0 : _d.inputRef);
236 setRef((_e = this.props.inputProps) === null || _e === void 0 ? void 0 : _e.inputRef, this.inputElement);
237 }
238 if (prevProps.value !== this.props.value) {
239 this.setState({ value: this.props.value });
240 }
241 };
242 DateInput.prototype.isDateInRange = function (value) {
243 return isDayInRange(value, [this.props.minDate, this.props.maxDate]);
244 };
245 DateInput.prototype.hasMonthChanged = function (prevDate, nextDate) {
246 return (prevDate == null) !== (nextDate == null) || nextDate.getMonth() !== prevDate.getMonth();
247 };
248 DateInput.prototype.hasTimeChanged = function (prevDate, nextDate) {
249 if (this.props.timePrecision == null) {
250 return false;
251 }
252 return ((prevDate == null) !== (nextDate == null) ||
253 nextDate.getHours() !== prevDate.getHours() ||
254 nextDate.getMinutes() !== prevDate.getMinutes() ||
255 nextDate.getSeconds() !== prevDate.getSeconds() ||
256 nextDate.getMilliseconds() !== prevDate.getMilliseconds());
257 };
258 DateInput.prototype.getRelatedTarget = function (e) {
259 var _a;
260 // Support IE11 (#2924)
261 return ((_a = e.relatedTarget) !== null && _a !== void 0 ? _a : document.activeElement);
262 };
263 /** safe wrapper around invoking input props event handler (prop defaults to undefined) */
264 DateInput.prototype.safeInvokeInputProp = function (name, e) {
265 var _a;
266 var _b = this.props.inputProps, inputProps = _b === void 0 ? {} : _b;
267 (_a = inputProps[name]) === null || _a === void 0 ? void 0 : _a.call(inputProps, e);
268 };
269 DateInput.prototype.parseDate = function (dateString) {
270 if (dateString === this.props.outOfRangeMessage || dateString === this.props.invalidDateMessage) {
271 return null;
272 }
273 var _a = this.props, locale = _a.locale, parseDate = _a.parseDate;
274 var newDate = parseDate(dateString, locale);
275 return newDate === false ? new Date(undefined) : newDate;
276 };
277 DateInput.prototype.formatDate = function (date) {
278 if (!isDateValid(date) || !this.isDateInRange(date)) {
279 return "";
280 }
281 var _a = this.props, locale = _a.locale, formatDate = _a.formatDate;
282 return formatDate(date, locale);
283 };
284 DateInput.displayName = "".concat(DISPLAYNAME_PREFIX, ".DateInput");
285 DateInput.defaultProps = {
286 closeOnSelection: true,
287 dayPickerProps: {},
288 disabled: false,
289 invalidDateMessage: "Invalid date",
290 maxDate: getDefaultMaxDate(),
291 minDate: getDefaultMinDate(),
292 outOfRangeMessage: "Out of range",
293 reverseMonthAndYearMenus: false,
294 };
295 return DateInput;
296}(AbstractPureComponent2));
297export { DateInput };
298//# sourceMappingURL=dateInput.js.map
\No newline at end of file