UNPKG

@blueprintjs/datetime

Version:

Components for interacting with dates and times

309 lines 16.4 kB
"use strict"; /* * Copyright 2015 Palantir Technologies, Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.TimePicker = void 0; const tslib_1 = require("tslib"); const classnames_1 = tslib_1.__importDefault(require("classnames")); const React = tslib_1.__importStar(require("react")); const core_1 = require("@blueprintjs/core"); const common_1 = require("../../common"); const timeUnit_1 = require("../../common/timeUnit"); const Utils = tslib_1.__importStar(require("../../common/utils")); /** * Time picker component. * * @see https://blueprintjs.com/docs/#datetime/timepicker */ class TimePicker extends React.Component { constructor(props) { super(props); this.timeInputIds = { [timeUnit_1.TimeUnit.HOUR_24]: core_1.Utils.uniqueId(timeUnit_1.TimeUnit.HOUR_24 + "-input"), [timeUnit_1.TimeUnit.HOUR_12]: core_1.Utils.uniqueId(timeUnit_1.TimeUnit.HOUR_12 + "-input"), [timeUnit_1.TimeUnit.MINUTE]: core_1.Utils.uniqueId(timeUnit_1.TimeUnit.MINUTE + "-input"), [timeUnit_1.TimeUnit.SECOND]: core_1.Utils.uniqueId(timeUnit_1.TimeUnit.SECOND + "-input"), [timeUnit_1.TimeUnit.MS]: core_1.Utils.uniqueId(timeUnit_1.TimeUnit.MS + "-input"), }; // begin method definitions: event handlers this.getInputChangeHandler = (unit) => (e) => { const text = getStringValueFromInputEvent(e); switch (unit) { case timeUnit_1.TimeUnit.HOUR_12: case timeUnit_1.TimeUnit.HOUR_24: this.setState({ hourText: text }); break; case timeUnit_1.TimeUnit.MINUTE: this.setState({ minuteText: text }); break; case timeUnit_1.TimeUnit.SECOND: this.setState({ secondText: text }); break; case timeUnit_1.TimeUnit.MS: this.setState({ millisecondText: text }); break; } }; this.getInputBlurHandler = (unit) => (e) => { var _a, _b; const text = getStringValueFromInputEvent(e); this.updateTime(parseInt(text, 10), unit); (_b = (_a = this.props).onBlur) === null || _b === void 0 ? void 0 : _b.call(_a, e, unit); }; this.getInputFocusHandler = (unit) => (e) => { var _a, _b; if (this.props.selectAllOnFocus) { e.currentTarget.select(); } (_b = (_a = this.props).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a, e, unit); }; this.getInputKeyDownHandler = (unit) => (e) => { var _a, _b; handleKeyEvent(e, { ArrowDown: () => this.decrementTime(unit), ArrowUp: () => this.incrementTime(unit), Enter: () => { e.currentTarget.blur(); }, }); (_b = (_a = this.props).onKeyDown) === null || _b === void 0 ? void 0 : _b.call(_a, e, unit); }; this.getInputKeyUpHandler = (unit) => (e) => { var _a, _b; (_b = (_a = this.props).onKeyUp) === null || _b === void 0 ? void 0 : _b.call(_a, e, unit); }; this.handleAmPmChange = (e) => { var _a; const isNextPm = e.currentTarget.value === "pm"; if (isNextPm !== this.state.isPm) { const value = (_a = this.state.value) !== null && _a !== void 0 ? _a : this.getInitialValue(); const hour = common_1.DateUtils.convert24HourMeridiem(value.getHours(), isNextPm); this.setState({ isPm: isNextPm }, () => this.updateTime(hour, timeUnit_1.TimeUnit.HOUR_24)); } }; this.incrementTime = (unit) => this.shiftTime(unit, 1); this.decrementTime = (unit) => this.shiftTime(unit, -1); this.state = this.getFullStateFromValue(this.getInitialValue(), props.useAmPm); } render() { const shouldRenderMilliseconds = this.props.precision === common_1.TimePrecision.MILLISECOND; const shouldRenderSeconds = shouldRenderMilliseconds || this.props.precision === common_1.TimePrecision.SECOND; const hourUnit = this.props.useAmPm ? timeUnit_1.TimeUnit.HOUR_12 : timeUnit_1.TimeUnit.HOUR_24; const classes = (0, classnames_1.default)(common_1.Classes.TIMEPICKER, this.props.className, { [core_1.Classes.DISABLED]: this.props.disabled, }); return (React.createElement("div", { className: classes }, React.createElement("div", { className: common_1.Classes.TIMEPICKER_ARROW_ROW }, this.maybeRenderArrowButton(true, hourUnit), this.maybeRenderArrowButton(true, timeUnit_1.TimeUnit.MINUTE), shouldRenderSeconds && this.maybeRenderArrowButton(true, timeUnit_1.TimeUnit.SECOND), shouldRenderMilliseconds && this.maybeRenderArrowButton(true, timeUnit_1.TimeUnit.MS)), React.createElement("div", { className: common_1.Classes.TIMEPICKER_INPUT_ROW }, this.renderInput(common_1.Classes.TIMEPICKER_HOUR, hourUnit, this.state.hourText), this.renderDivider(), this.renderInput(common_1.Classes.TIMEPICKER_MINUTE, timeUnit_1.TimeUnit.MINUTE, this.state.minuteText), shouldRenderSeconds && this.renderDivider(), shouldRenderSeconds && this.renderInput(common_1.Classes.TIMEPICKER_SECOND, timeUnit_1.TimeUnit.SECOND, this.state.secondText), shouldRenderMilliseconds && this.renderDivider("."), shouldRenderMilliseconds && this.renderInput(common_1.Classes.TIMEPICKER_MILLISECOND, timeUnit_1.TimeUnit.MS, this.state.millisecondText)), this.maybeRenderAmPm(), React.createElement("div", { className: common_1.Classes.TIMEPICKER_ARROW_ROW }, this.maybeRenderArrowButton(false, hourUnit), this.maybeRenderArrowButton(false, timeUnit_1.TimeUnit.MINUTE), shouldRenderSeconds && this.maybeRenderArrowButton(false, timeUnit_1.TimeUnit.SECOND), shouldRenderMilliseconds && this.maybeRenderArrowButton(false, timeUnit_1.TimeUnit.MS)))); } componentDidUpdate(prevProps) { var _a, _b, _c, _d; const didMinTimeChange = prevProps.minTime !== this.props.minTime; const didMaxTimeChange = prevProps.maxTime !== this.props.maxTime; const didBoundsChange = didMinTimeChange || didMaxTimeChange; const didPropValueChange = prevProps.value !== this.props.value; const shouldStateUpdate = didBoundsChange || didPropValueChange; let value = this.state.value; if (this.props.value == null) { value = this.getInitialValue(); } if (didBoundsChange) { value = common_1.DateUtils.getTimeInRange((_a = this.state.value) !== null && _a !== void 0 ? _a : this.getInitialValue(), (_b = this.props.minTime) !== null && _b !== void 0 ? _b : (0, timeUnit_1.getDefaultMinTime)(), (_c = this.props.maxTime) !== null && _c !== void 0 ? _c : (0, timeUnit_1.getDefaultMaxTime)()); } if (this.props.value != null && !common_1.DateUtils.isSameTime(this.props.value, (_d = prevProps.value) !== null && _d !== void 0 ? _d : null)) { value = this.props.value; } if (shouldStateUpdate) { this.setState(this.getFullStateFromValue(value, this.props.useAmPm)); } } // begin method definitions: rendering maybeRenderArrowButton(isDirectionUp, timeUnit) { if (!this.props.showArrowButtons) { return null; } const classes = (0, classnames_1.default)(common_1.Classes.TIMEPICKER_ARROW_BUTTON, (0, timeUnit_1.getTimeUnitClassName)(timeUnit)); const onClick = () => (isDirectionUp ? this.incrementTime : this.decrementTime)(timeUnit); const label = `${isDirectionUp ? "Increase" : "Decrease"} ${(0, timeUnit_1.getTimeUnitPrintStr)(timeUnit)}`; // set tabIndex=-1 to ensure a valid FocusEvent relatedTarget when focused return (React.createElement("span", { "aria-controls": this.timeInputIds[timeUnit], "aria-label": label, tabIndex: -1, className: classes, onClick: onClick }, React.createElement(core_1.Icon, { icon: isDirectionUp ? "chevron-up" : "chevron-down", title: label }))); } renderDivider(text = ":") { return React.createElement("span", { className: common_1.Classes.TIMEPICKER_DIVIDER_TEXT }, text); } renderInput(className, unit, value) { const isValid = value != null ? (0, timeUnit_1.isTimeUnitValid)(unit, parseInt(value, 10)) : false; const isHour = unit === timeUnit_1.TimeUnit.HOUR_12 || unit === timeUnit_1.TimeUnit.HOUR_24; return (React.createElement("input", { "aria-label": (0, timeUnit_1.getTimeUnitPrintStr)(unit), className: (0, classnames_1.default)(common_1.Classes.TIMEPICKER_INPUT, { [core_1.Classes.intentClass(core_1.Intent.DANGER)]: !isValid }, className), id: this.timeInputIds[unit], min: 0, max: (0, timeUnit_1.getTimeUnitMax)(unit), onBlur: this.getInputBlurHandler(unit), onChange: this.getInputChangeHandler(unit), onFocus: this.getInputFocusHandler(unit), onKeyDown: this.getInputKeyDownHandler(unit), onKeyUp: this.getInputKeyUpHandler(unit), role: this.props.showArrowButtons ? "spinbutton" : undefined, type: "number", value: value, disabled: this.props.disabled, autoFocus: isHour && this.props.autoFocus })); } maybeRenderAmPm() { if (!this.props.useAmPm) { return null; } return (React.createElement(core_1.HTMLSelect, { className: common_1.Classes.TIMEPICKER_AMPM_SELECT, disabled: this.props.disabled, onChange: this.handleAmPmChange, value: this.state.isPm ? "pm" : "am" }, React.createElement("option", { value: "am" }, "AM"), React.createElement("option", { value: "pm" }, "PM"))); } // begin method definitions: state modification /** * Generates a full TimePickerState object with all text fields set to formatted strings based on value */ getFullStateFromValue(value, useAmPm = false) { var _a, _b; value = value !== null && value !== void 0 ? value : this.getInitialValue(); const timeInRange = common_1.DateUtils.getTimeInRange(value, (_a = this.props.minTime) !== null && _a !== void 0 ? _a : (0, timeUnit_1.getDefaultMinTime)(), (_b = this.props.maxTime) !== null && _b !== void 0 ? _b : (0, timeUnit_1.getDefaultMaxTime)()); const hourUnit = useAmPm ? timeUnit_1.TimeUnit.HOUR_12 : timeUnit_1.TimeUnit.HOUR_24; /* eslint-disable sort-keys */ return { hourText: formatTime(timeInRange.getHours(), hourUnit), minuteText: formatTime(timeInRange.getMinutes(), timeUnit_1.TimeUnit.MINUTE), secondText: formatTime(timeInRange.getSeconds(), timeUnit_1.TimeUnit.SECOND), millisecondText: formatTime(timeInRange.getMilliseconds(), timeUnit_1.TimeUnit.MS), value: timeInRange, isPm: common_1.DateUtils.getIsPmFrom24Hour(timeInRange.getHours()), }; /* eslint-enable sort-keys */ } shiftTime(unit, amount) { var _a; if (this.props.disabled) { return; } const newTime = (0, timeUnit_1.getTimeUnit)(unit, (_a = this.state.value) !== null && _a !== void 0 ? _a : this.getInitialValue()) + amount; this.updateTime((0, timeUnit_1.wrapTimeAtUnit)(unit, newTime), unit); } updateTime(time, unit) { var _a, _b, _c; const value = (_a = this.state.value) !== null && _a !== void 0 ? _a : this.getInitialValue(); const newValue = common_1.DateUtils.clone(value); if ((0, timeUnit_1.isTimeUnitValid)(unit, time)) { (0, timeUnit_1.setTimeUnit)(unit, time, newValue, this.state.isPm); if (common_1.DateUtils.isTimeInRange(newValue, (_b = this.props.minTime) !== null && _b !== void 0 ? _b : (0, timeUnit_1.getDefaultMinTime)(), (_c = this.props.maxTime) !== null && _c !== void 0 ? _c : (0, timeUnit_1.getDefaultMaxTime)())) { this.updateState({ value: newValue }); } else { this.updateState(this.getFullStateFromValue(value, this.props.useAmPm)); } } else { this.updateState(this.getFullStateFromValue(value, this.props.useAmPm)); } } updateState(state) { var _a, _b, _c; let newState = state; const hasNewValue = newState.value != null && !common_1.DateUtils.isSameTime(newState.value, (_a = this.state.value) !== null && _a !== void 0 ? _a : null); if (this.props.value == null) { // component is uncontrolled if (hasNewValue) { newState = this.getFullStateFromValue(newState.value, this.props.useAmPm); } this.setState(newState); } else { // component is controlled, and there's a new value // so set inputs' text based off of _old_ value and later fire onChange with new value if (hasNewValue) { this.setState(this.getFullStateFromValue(this.state.value, this.props.useAmPm)); } else { // no new value, this means only text has changed (from user typing) // we want inputs to change, so update state with new text for the inputs // but don't change actual value this.setState({ ...newState, value: this.state.value != null ? common_1.DateUtils.clone(this.state.value) : undefined, }); } } if (hasNewValue && newState.value != null) { (_c = (_b = this.props).onChange) === null || _c === void 0 ? void 0 : _c.call(_b, newState.value); } } getInitialValue() { var _a; const minTime = (_a = this.props.minTime) !== null && _a !== void 0 ? _a : (0, timeUnit_1.getDefaultMinTime)(); let value = minTime; if (this.props.value != null) { value = this.props.value; } else if (this.props.defaultValue != null) { value = this.props.defaultValue; } return value; } } exports.TimePicker = TimePicker; TimePicker.defaultProps = { autoFocus: false, disabled: false, maxTime: (0, timeUnit_1.getDefaultMaxTime)(), minTime: (0, timeUnit_1.getDefaultMinTime)(), precision: common_1.TimePrecision.MINUTE, selectAllOnFocus: false, showArrowButtons: false, useAmPm: false, }; TimePicker.displayName = `${core_1.DISPLAYNAME_PREFIX}.TimePicker`; function formatTime(time, unit) { switch (unit) { case timeUnit_1.TimeUnit.HOUR_24: return time.toString(); case timeUnit_1.TimeUnit.HOUR_12: return common_1.DateUtils.get12HourFrom24Hour(time).toString(); case timeUnit_1.TimeUnit.MINUTE: case timeUnit_1.TimeUnit.SECOND: return Utils.padWithZeroes(time.toString(), 2); case timeUnit_1.TimeUnit.MS: return Utils.padWithZeroes(time.toString(), 3); default: throw Error("Invalid TimeUnit"); } } function getStringValueFromInputEvent(e) { return e.target.value; } function handleKeyEvent(e, actions, preventDefault = true) { for (const key of Object.keys(actions)) { if (e.key === key) { if (preventDefault) { e.preventDefault(); } actions[key](); } } } //# sourceMappingURL=timePicker.js.map