@capaj/react-datetime
Version:
A lightweight but complete datetime picker React.js component
438 lines • 16.3 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const object_assign_1 = __importDefault(require("object-assign"));
const moment_1 = __importDefault(require("moment"));
const react_1 = __importDefault(require("react"));
const CalendarContainer_1 = __importDefault(require("./CalendarContainer"));
const viewModes = Object.freeze({
YEARS: 'years',
MONTHS: 'months',
DAYS: 'days',
TIME: 'time'
});
class Datetime extends react_1.default.Component {
constructor(props, context) {
super(props, context);
this.onInputChange = (e) => {
const value = e.target === null ? e : e.target.value;
const localMoment = this.localMoment(value, this.state.inputFormat);
const update = {
inputValue: value
};
if (localMoment.isValid() && !this.props.value) {
update.selectedDate = localMoment;
update.viewDate = localMoment.clone().startOf('month');
}
else {
update.selectedDate = null;
}
return this.setState(update, function () {
return this.props.onChange(localMoment.isValid() ? localMoment : this.state.inputValue);
});
};
this.onInputKey = ({ which }) => {
if (which === 9 && this.props.closeOnTab) {
this.closeCalendar();
}
};
this.showView = (view) => {
return () => {
this.state.currentView !== view && this.props.onViewModeChange(view);
this.setState({
currentView: view
});
};
};
this.setDate = (type) => {
const nextViews = {
month: viewModes.DAYS,
year: viewModes.MONTHS
};
return ({ target }) => {
this.setState({
viewDate: this.state.viewDate
.clone()[type](parseInt(target.getAttribute('data-value'), 10))
.startOf(type),
currentView: nextViews[type]
});
this.props.onViewModeChange(nextViews[type]);
};
};
this.subtractTime = (amount, type, toSelected) => {
return () => {
this.props.onNavigateBack(amount, type);
this.updateTime('subtract', amount, type, toSelected);
};
};
this.addTime = (amount, type, toSelected) => {
return () => {
this.props.onNavigateForward(amount, type);
this.updateTime('add', amount, type, toSelected);
};
};
this.allowedSetTime = ['hours', 'minutes', 'seconds', 'milliseconds'];
this.setTime = (type, value) => {
let index = this.allowedSetTime.indexOf(type) + 1;
const state = this.state;
const date = (state.selectedDate || state.viewDate).clone();
let nextType;
date[type](value);
for (; index < this.allowedSetTime.length; index++) {
nextType = this.allowedSetTime[index];
date[nextType](date[nextType]());
}
if (!this.props.value) {
this.setState({
selectedDate: date,
inputValue: date.format(state.inputFormat)
});
}
this.props.onChange(date);
};
this.updateSelectedDate = (e, close) => {
const target = e.target;
let modifier = 0;
const viewDate = this.state.viewDate;
const currentDate = this.state.selectedDate || viewDate;
let date;
if (target.className.includes('rdtDay')) {
if (target.className.includes('rdtNew'))
modifier = 1;
else if (target.className.includes('rdtOld'))
modifier = -1;
date = viewDate
.clone()
.month(viewDate.month() + modifier)
.date(parseInt(target.getAttribute('data-value'), 10));
}
else if (target.className.includes('rdtMonth')) {
date = viewDate
.clone()
.month(parseInt(target.getAttribute('data-value'), 10))
.date(currentDate.date());
}
else if (target.className.includes('rdtYear')) {
date = viewDate
.clone()
.month(currentDate.month())
.date(currentDate.date())
.year(parseInt(target.getAttribute('data-value'), 10));
}
date
.hours(currentDate.hours())
.minutes(currentDate.minutes())
.seconds(currentDate.seconds())
.milliseconds(currentDate.milliseconds());
if (!this.props.value) {
const open = !(this.props.closeOnSelect && close);
if (!open) {
this.props.onBlur(date);
}
this.setState({
selectedDate: date,
viewDate: date.clone().startOf('month'),
inputValue: date.format(this.state.inputFormat),
open
});
}
else {
if (this.props.closeOnSelect && close) {
this.closeCalendar();
}
}
this.props.onChange(date);
};
this.openCalendar = (e) => {
if (!this.state.open) {
this.setState({
open: true
}, () => {
this.props.onFocus && this.props.onFocus(e);
});
}
};
this.closeCalendar = () => {
this.setState({
open: false
}, function () {
this.props.onBlur(this.state.selectedDate || this.state.inputValue);
});
};
this.handleClickOutside = () => {
if (this.props.input &&
this.state.open &&
!this.props.open &&
!this.props.disableOnClickOutside) {
this.setState({
open: false
}, function () {
this.props.onBlur(this.state.selectedDate || this.state.inputValue);
});
}
};
const state = this.getStateFromProps(this.props);
this.state = state;
}
parseDate(date, { datetime }) {
let parsedDate;
if (date && typeof date === 'string')
parsedDate = this.localMoment(date, datetime);
else if (date)
parsedDate = this.localMoment(date);
if (parsedDate && !parsedDate.isValid())
parsedDate = null;
return parsedDate;
}
getStateFromProps(props) {
const formats = this.getFormats(props);
const date = props.value || props.defaultValue;
let selectedDate;
let viewDate;
let updateOn;
let inputValue;
let { open } = props;
selectedDate = this.parseDate(date, formats);
viewDate = this.parseDate(props.viewDate, formats);
viewDate = selectedDate
? selectedDate.clone().startOf('month')
: viewDate
? viewDate.clone().startOf('month')
: this.localMoment().startOf('month');
updateOn = this.getUpdateOn(formats);
if (selectedDate)
inputValue = selectedDate.format(formats.datetime);
else if (date.isValid && !date.isValid())
inputValue = '';
else
inputValue = date || '';
if (props.open === undefined) {
open = !props.input;
}
let currentView = props.dateFormat
? props.viewMode || updateOn || viewModes.DAYS
: viewModes.TIME;
const state = {
updateOn,
inputFormat: formats.datetime,
viewDate,
selectedDate,
inputValue,
open,
currentView
};
return state;
}
getUpdateOn({ date }) {
if (date.match(/[lLD]/)) {
return viewModes.DAYS;
}
else if (date.includes('M')) {
return viewModes.MONTHS;
}
else if (date.includes('Y')) {
return viewModes.YEARS;
}
return viewModes.DAYS;
}
getFormats(props) {
const formats = {
date: props.dateFormat || '',
time: props.timeFormat || ''
};
const locale = this.localMoment(props.date, null, props).localeData();
if (formats.date === true) {
formats.date = locale.longDateFormat('L');
}
else if (this.getUpdateOn(formats) !== viewModes.DAYS) {
formats.time = '';
}
if (formats.time === true) {
formats.time = locale.longDateFormat('LT');
}
formats.datetime =
formats.date && formats.time
? `${formats.date} ${formats.time}`
: formats.date || formats.time;
return formats;
}
componentWillReceiveProps(nextProps) {
const formats = this.getFormats(nextProps);
let updatedState = {};
if (nextProps.value !== this.props.value ||
formats.datetime !== this.getFormats(this.props).datetime) {
updatedState = this.getStateFromProps(nextProps);
}
if (updatedState.open === undefined) {
if (typeof nextProps.open !== 'undefined') {
updatedState.open = nextProps.open;
}
else if (this.props.closeOnSelect &&
this.state.currentView !== viewModes.TIME) {
updatedState.open = false;
}
else {
updatedState.open = this.state.open;
}
}
if (nextProps.viewMode !== this.props.viewMode) {
updatedState.currentView = nextProps.viewMode;
}
if (nextProps.locale !== this.props.locale) {
if (this.state.viewDate) {
const updatedViewDate = this.state.viewDate
.clone()
.locale(nextProps.locale);
updatedState.viewDate = updatedViewDate;
}
if (this.state.selectedDate) {
const updatedSelectedDate = this.state.selectedDate
.clone()
.locale(nextProps.locale);
updatedState.selectedDate = updatedSelectedDate;
updatedState.inputValue = updatedSelectedDate.format(formats.datetime);
}
}
if (nextProps.timezone !== this.props.timezone) {
if (nextProps.timezone) {
if (this.state.viewDate)
updatedState.viewDate = this.state.viewDate
.clone()
.tz(nextProps.timezone, true);
if (this.state.selectedDate) {
updatedState.selectedDate = this.state.selectedDate
.clone()
.tz(nextProps.timezone, true);
updatedState.inputValue = updatedState.selectedDate.format(formats.datetime);
}
}
else {
if (this.state.viewDate)
updatedState.viewDate = this.state.viewDate.clone().local();
if (this.state.selectedDate) {
updatedState.selectedDate = this.state.selectedDate.clone().local();
updatedState.inputValue = updatedState.selectedDate.format(formats.datetime);
}
}
}
if (nextProps.viewDate !== this.props.viewDate) {
updatedState.viewDate = moment_1.default(nextProps.viewDate);
}
this.setState(updatedState);
}
updateTime(op, amount, type, toSelected) {
const update = {};
const date = toSelected ? 'selectedDate' : 'viewDate';
update[date] = this.state[date].clone()[op](amount, type);
this.setState(update);
}
localMoment(date, format, props) {
props = props || this.props;
const momentFn = props.timezone
? (time) => moment_1.default(time).tz(props.timezone, true)
: moment_1.default;
const m = momentFn(date, format, props.strictParsing);
if (props.locale)
m.locale(props.locale);
return m;
}
getComponentProps() {
const componentProps = {
fromProps: [
'value',
'isValidDate',
'renderDay',
'renderMonth',
'renderYear',
'timeConstraints'
],
fromState: ['viewDate', 'selectedDate', 'updateOn'],
fromThis: [
'setDate',
'setTime',
'showView',
'addTime',
'subtractTime',
'updateSelectedDate',
'localMoment',
'handleClickOutside'
]
};
const formats = this.getFormats(this.props);
const props = {
dateFormat: formats.date,
timeFormat: formats.time
};
componentProps.fromProps.forEach((name) => {
props[name] = this.props[name];
});
componentProps.fromState.forEach((name) => {
props[name] = this.state[name];
});
componentProps.fromThis.forEach((name) => {
props[name] = this[name];
});
return props;
}
render() {
let className = `rdt${this.props.className
? Array.isArray(this.props.className)
? ` ${this.props.className.join(' ')}`
: ` ${this.props.className}`
: ''}`;
let children = [];
if (this.props.input) {
const finalInputProps = object_assign_1.default({
type: 'text',
className: 'form-control',
onClick: this.openCalendar,
onFocus: this.openCalendar,
onChange: this.onInputChange,
onKeyDown: this.onInputKey,
value: this.state && this.state.inputValue
}, this.props.inputProps);
if (this.props.renderInput) {
children = [
react_1.default.createElement("div", { key: "i" }, this.props.renderInput(finalInputProps, this.openCalendar, this.closeCalendar))
];
}
else {
children = [
react_1.default.createElement("input", Object.assign({}, object_assign_1.default({
key: 'i'
}, finalInputProps)))
];
}
}
else {
className += ' rdtStatic';
}
if (this.state.open)
className += ' rdtOpen';
return (react_1.default.createElement("div", { className: className }, children.concat(react_1.default.createElement("div", { key: "dt", className: "rdtPicker" },
react_1.default.createElement(CalendarContainer_1.default, { view: this.state.currentView, viewProps: this.getComponentProps(), onClickOutside: this.handleClickOutside })))));
}
}
Datetime.defaultProps = {
className: '',
defaultValue: '',
inputProps: {},
input: true,
onFocus() { },
onBlur() { },
onChange() { },
onViewModeChange() { },
onNavigateBack() { },
onNavigateForward() { },
timeFormat: true,
timeConstraints: {},
dateFormat: true,
strictParsing: true,
closeOnSelect: false,
closeOnTab: true,
timezone: null
};
exports.default = Datetime;
//# sourceMappingURL=DateTime.js.map