react-native-calendars-datepicker
Version:
Customizable date picker for React Native that supports Hijri calendar
495 lines (490 loc) • 19.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _utils = require("./utils");
var _calendarContext = require("./calendar-context");
var _enums = require("./enums");
var _calendar = _interopRequireDefault(require("./components/calendar"));
var _dayjs = _interopRequireDefault(require("dayjs"));
var _localeData = _interopRequireDefault(require("dayjs/plugin/localeData"));
var _relativeTime = _interopRequireDefault(require("dayjs/plugin/relativeTime"));
var _localizedFormat = _interopRequireDefault(require("dayjs/plugin/localizedFormat"));
var _utc = _interopRequireDefault(require("dayjs/plugin/utc"));
var _timezone = _interopRequireDefault(require("dayjs/plugin/timezone"));
var _duration = _interopRequireDefault(require("dayjs/plugin/duration"));
var _usePrevious = require("./hooks/use-previous");
var _jalaliPluginDayjs = _interopRequireDefault(require("jalali-plugin-dayjs"));
var _dayjsCalendarsystems = _interopRequireDefault(require("@calidy/dayjs-calendarsystems"));
var _HijriCalendarSystem = _interopRequireDefault(require("@calidy/dayjs-calendarsystems/calendarSystems/HijriCalendarSystem"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
_dayjs.default.extend(_localeData.default);
_dayjs.default.extend(_relativeTime.default);
_dayjs.default.extend(_localizedFormat.default);
_dayjs.default.extend(_utc.default);
_dayjs.default.extend(_timezone.default);
_dayjs.default.extend(_duration.default);
_dayjs.default.extend(_jalaliPluginDayjs.default);
_dayjs.default.extend(_dayjsCalendarsystems.default);
/* Register new calendar system, here I'm using Hijri for other sytems visit URL: https://github.com/calidy-com/dayjs-calendarsystems */
_dayjs.default.registerCalendarSystem('islamic', new _HijriCalendarSystem.default());
const DateTimePicker = props => {
const {
mode = 'single',
calendar = 'gregory',
locale = 'en',
numerals = 'latn',
timeZone,
showOutsideDays = false,
timePicker = false,
firstDayOfWeek,
// startYear,
// endYear,
minDate,
maxDate,
enabledDates,
disabledDates,
date,
startDate,
endDate,
dates,
min,
max,
onChange,
initialView = 'day',
containerHeight = _enums.CONTAINER_HEIGHT,
weekdaysHeight = _enums.WEEKDAYS_HEIGHT,
style = {},
className = '',
classNames = {},
styles = {},
navigationPosition,
weekdaysFormat = 'min',
monthsFormat = 'full',
monthCaptionFormat = 'full',
multiRangeMode,
hideHeader,
hideWeekdays,
disableMonthPicker,
disableYearPicker,
components = {},
month,
year,
onMonthChange = () => {},
onYearChange = () => {},
use12Hours
} = props;
_dayjs.default.tz.setDefault(timeZone);
if (calendar !== 'islamic') {
_dayjs.default.calendar(calendar);
}
_dayjs.default.locale(locale);
const prevTimezone = (0, _usePrevious.usePrevious)(timeZone);
const initialCalendarView = (0, _react.useMemo)(() => mode !== 'single' && initialView === 'time' ? 'day' : initialView, [mode, initialView]);
const firstDay = (0, _react.useMemo)(() => firstDayOfWeek && firstDayOfWeek > 0 && firstDayOfWeek <= 6 ? firstDayOfWeek : 0, [firstDayOfWeek]);
const initialState = (0, _react.useMemo)(() => {
let initialDate = (0, _dayjs.default)().tz(timeZone);
if (calendar === 'islamic') {
initialDate = (0, _utils.getDayjs)(initialDate, calendar);
}
if (mode === 'single' && date) {
initialDate = (0, _utils.getDayjs)(date, calendar);
}
if (mode === 'range' && startDate) {
initialDate = (0, _utils.getDayjs)(startDate, calendar);
}
if (mode === 'multiple' && dates && dates.length > 0) {
initialDate = (0, _utils.getDayjs)(dates[0], calendar);
}
if (minDate && initialDate.isBefore(minDate)) {
initialDate = (0, _utils.getDayjs)(minDate, calendar);
}
if (month !== undefined && month && month >= 0 && month <= 11) {
initialDate = initialDate.month(month);
}
if (year !== undefined && year >= 0) {
initialDate = initialDate.year(year);
}
let _date = date ? (0, _utils.getDayjs)(date, calendar) : date;
if (_date && maxDate && (0, _utils.getDayjs)(_date, calendar).isAfter(maxDate)) {
_date = (0, _utils.getDayjs)(maxDate, calendar);
}
if (_date && minDate && (0, _utils.getDayjs)(_date, calendar).isBefore(minDate)) {
_date = (0, _dayjs.default)(minDate);
}
let start = startDate ? (0, _utils.getDayjs)(startDate, calendar) : startDate;
if (start && maxDate && (0, _utils.getDayjs)(start, calendar).isAfter(maxDate)) {
start = (0, _utils.getDayjs)(maxDate, calendar);
}
if (start && minDate && (0, _utils.getDayjs)(start, calendar).isBefore(minDate)) {
start = (0, _utils.getDayjs)(minDate, calendar);
}
let end = endDate ? (0, _utils.getDayjs)(endDate, calendar) : endDate;
if (end && maxDate && (0, _utils.getDayjs)(end, calendar).isAfter(maxDate)) {
end = (0, _utils.getDayjs)(maxDate, calendar);
}
if (end && minDate && (0, _utils.getDayjs)(end, calendar).isBefore(minDate)) {
end = (0, _utils.getDayjs)(minDate, calendar);
}
return {
date: _date,
startDate: start,
endDate: end,
dates,
calendarView: initialCalendarView,
currentDate: initialDate,
currentYear: initialDate.year(),
isRTL: calendar === 'jalali' || _reactNative.I18nManager.isRTL
};
}, [mode, calendar, date, startDate, endDate, dates, minDate, maxDate, month, year, timeZone, initialCalendarView]);
const [state, dispatch] = (0, _react.useReducer)((prevState, action) => {
switch (action.type) {
case _enums.CalendarActionKind.SET_CALENDAR_VIEW:
return {
...prevState,
calendarView: action.payload
};
case _enums.CalendarActionKind.CHANGE_CURRENT_DATE:
return {
...prevState,
currentDate: action.payload
};
case _enums.CalendarActionKind.CHANGE_CURRENT_YEAR:
return {
...prevState,
currentYear: action.payload
};
case _enums.CalendarActionKind.CHANGE_SELECTED_DATE:
const {
date: selectedDate
} = action.payload;
return {
...prevState,
date: selectedDate,
currentDate: selectedDate
};
case _enums.CalendarActionKind.CHANGE_SELECTED_RANGE:
const {
startDate: start,
endDate: end
} = action.payload;
return {
...prevState,
startDate: start,
endDate: end
};
case _enums.CalendarActionKind.CHANGE_SELECTED_MULTIPLE:
const {
dates: selectedDates
} = action.payload;
return {
...prevState,
dates: selectedDates
};
case _enums.CalendarActionKind.SET_IS_RTL:
return {
...prevState,
isRTL: action.payload
};
case _enums.CalendarActionKind.RESET_STATE:
return action.payload;
default:
return prevState;
}
}, initialState);
const stateRef = (0, _react.useRef)(state);
stateRef.current = state;
(0, _react.useEffect)(() => {
const newState = {
...initialState,
isRTL: calendar === 'jalali' || _reactNative.I18nManager.isRTL
};
dispatch({
type: _enums.CalendarActionKind.RESET_STATE,
payload: newState
});
}, [calendar]);
(0, _react.useEffect)(() => {
if (prevTimezone !== timeZone) {
const newDate = (0, _dayjs.default)().tz(timeZone);
dispatch({
type: _enums.CalendarActionKind.CHANGE_CURRENT_DATE,
payload: newDate
});
}
}, [timeZone, prevTimezone]);
(0, _react.useEffect)(() => {
if (mode === 'single') {
let _date = (date && (timePicker ? _dayjs.default.tz(date, timeZone) : (0, _utils.getStartOfDay)(_dayjs.default.tz(date, timeZone), calendar))) ?? date;
if (_date && maxDate && _dayjs.default.tz(_date, timeZone).isAfter(maxDate)) {
_date = _dayjs.default.tz(maxDate, timeZone);
}
if (_date && minDate && _dayjs.default.tz(_date, timeZone).isBefore(minDate)) {
_date = _dayjs.default.tz(minDate, timeZone);
}
if (_date) {
dispatch({
type: _enums.CalendarActionKind.CHANGE_SELECTED_DATE,
payload: {
date: (0, _utils.getDayjs)(_date, calendar)
}
});
}
if (prevTimezone !== timeZone) {
onChange({
date: _date ? (0, _utils.getDayjs)(_date, calendar).toDate() : _date
});
}
} else if (mode === 'range') {
let start = startDate ? _dayjs.default.tz(startDate, timeZone) : startDate;
if (start && maxDate && _dayjs.default.tz(start, timeZone).isAfter(maxDate)) {
start = _dayjs.default.tz(maxDate, timeZone);
}
if (start && minDate && _dayjs.default.tz(start, timeZone).isBefore(minDate)) {
start = _dayjs.default.tz(minDate, timeZone);
}
let end = endDate ? _dayjs.default.tz(endDate, timeZone) : endDate;
if (end && maxDate && _dayjs.default.tz(end, timeZone).isAfter(maxDate)) {
end = _dayjs.default.tz(maxDate, timeZone);
}
if (end && minDate && _dayjs.default.tz(end, timeZone).isBefore(minDate)) {
end = _dayjs.default.tz(minDate, timeZone);
}
dispatch({
type: _enums.CalendarActionKind.CHANGE_SELECTED_RANGE,
payload: {
startDate: start,
endDate: end
}
});
if (prevTimezone !== timeZone) {
onChange({
startDate: start ? (0, _utils.getDayjs)(start, calendar).toDate() : start,
endDate: end ? (0, _utils.getDayjs)(end, calendar).toDate() : end
});
}
} else if (mode === 'multiple') {
const _dates = dates === null || dates === void 0 ? void 0 : dates.map(date => (0, _utils.getDayjs)(date, calendar).tz(timeZone));
dispatch({
type: _enums.CalendarActionKind.CHANGE_SELECTED_MULTIPLE,
payload: {
dates: _dates
}
});
if (prevTimezone !== timeZone) {
onChange({
dates: _dates.map(item => (0, _utils.getDayjs)(item, calendar).toDate()),
change: 'updated'
});
}
}
}, [mode, date, startDate, endDate, dates, minDate, maxDate, timePicker, prevTimezone, timeZone, calendar, onChange]);
const setCalendarView = (0, _react.useCallback)(view => {
dispatch({
type: _enums.CalendarActionKind.SET_CALENDAR_VIEW,
payload: view
});
}, []);
const onSelectDate = (0, _react.useCallback)(selectedDate => {
if (onChange) {
if (mode === 'single') {
const newDate = timePicker ? _dayjs.default.tz(selectedDate, timeZone) : _dayjs.default.tz((0, _utils.getStartOfDay)(selectedDate, calendar), timeZone);
dispatch({
type: _enums.CalendarActionKind.CHANGE_CURRENT_DATE,
payload: newDate
});
onChange({
date: newDate ? (0, _utils.getDayjs)(newDate, calendar).toDate() : newDate
});
} else if (mode === 'range') {
// set time to 00:00:00
let start = (0, _utils.removeTime)(stateRef.current.startDate, timeZone, calendar);
let end = (0, _utils.removeTime)(stateRef.current.endDate, timeZone, calendar);
const selected = (0, _utils.removeTime)(selectedDate, timeZone, calendar);
let isStart = true;
let isReset = false;
const selectedUnix = (0, _utils.dateToUnix)(selected, calendar);
const startUnix = (0, _utils.dateToUnix)(start, calendar);
const endUnix = (0, _utils.dateToUnix)(end, calendar);
if (selectedUnix !== endUnix && selectedUnix >= startUnix && startUnix !== endUnix) {
isStart = false;
} else if (start && selectedUnix === startUnix) {
isReset = true;
}
if (start && end) {
if (startUnix === endUnix && selectedUnix > startUnix) {
isStart = false;
}
if (selectedUnix > startUnix && selectedUnix === endUnix) {
end = undefined;
}
}
if (start && !end && selectedUnix < startUnix) {
end = start;
}
if (isStart && end && (min || max)) {
const numberOfDays = (0, _utils.getDayjs)(end, calendar).diff(selected, 'day');
if (max && numberOfDays > max || min && numberOfDays < min) {
isStart = true;
end = undefined;
}
}
if (!isStart && start && (min || max)) {
const numberOfDays = (0, _utils.getDayjs)(selected, calendar).diff(start, 'day');
if (selectedUnix === startUnix) {
isReset = true;
} else if (max && numberOfDays > max || min && numberOfDays < min) {
isStart = true;
end = undefined;
}
}
if (isReset) {
onChange({
startDate: undefined,
endDate: undefined
});
} else {
onChange({
startDate: isStart ? (0, _utils.getDayjs)(selected, calendar).toDate() : start ? _dayjs.default.tz(start).toDate() : start,
endDate: !isStart ? _dayjs.default.tz((0, _utils.getEndOfDay)(selected, calendar), timeZone).toDate() : end ? _dayjs.default.tz((0, _utils.getEndOfDay)(end, calendar), timeZone).toDate() : end
});
}
} else if (mode === 'multiple') {
const safeDates = stateRef.current.dates || [];
const newDate = _dayjs.default.tz((0, _utils.getDayjs)(selectedDate, calendar), timeZone).startOf('day');
const exists = safeDates.some(ed => (0, _utils.areDatesOnSameDay)(ed, newDate, calendar));
const newDates = exists ? safeDates.filter(ed => !(0, _utils.areDatesOnSameDay)(ed, newDate, calendar)) : [...safeDates, newDate];
if (max && newDates.length > max) {
return;
}
newDates.sort((a, b) => (0, _dayjs.default)(a).isAfter((0, _dayjs.default)(b)) ? 1 : -1);
const _dates = newDates.map(date => (0, _dayjs.default)(date).tz(timeZone));
onChange({
dates: _dates.map(item => (0, _dayjs.default)(item).toDate()),
datePressed: newDate ? (0, _dayjs.default)(newDate).toDate() : newDate,
change: exists ? 'removed' : 'added'
});
}
}
}, [mode, timePicker, min, max, timeZone]);
// set the active displayed month
const onSelectMonth = (0, _react.useCallback)(value => {
const currentMonth = stateRef.current.currentDate.month();
const newDate = stateRef.current.currentDate.month(value);
// Only call onMonthChange if the month actually changed
if (value !== currentMonth) {
onMonthChange(value);
}
dispatch({
type: _enums.CalendarActionKind.CHANGE_CURRENT_DATE,
payload: (0, _utils.getDayjs)(newDate, calendar)
});
setCalendarView('day');
}, [calendar, setCalendarView, onMonthChange]);
// set the active displayed year
const onSelectYear = (0, _react.useCallback)(value => {
const currentYear = (0, _utils.getDayjs)(stateRef.current.currentDate, calendar).year();
const newDate = (0, _utils.getDayjs)(stateRef.current.currentDate, calendar).year(value);
// Only call onYearChange if the year actually changed
if (value !== currentYear) {
onYearChange(value);
}
dispatch({
type: _enums.CalendarActionKind.CHANGE_CURRENT_DATE,
payload: newDate
});
setCalendarView('day');
}, [calendar, setCalendarView, onYearChange]);
const onChangeMonth = (0, _react.useCallback)(value => {
const currentMonth = stateRef.current.currentDate.month();
const newDate = stateRef.current.currentDate.month(currentMonth + value);
dispatch({
type: _enums.CalendarActionKind.CHANGE_CURRENT_DATE,
payload: newDate
});
}, []);
const onChangeYear = (0, _react.useCallback)(value => {
dispatch({
type: _enums.CalendarActionKind.CHANGE_CURRENT_YEAR,
payload: value
});
}, [dispatch]);
(0, _react.useEffect)(() => {
if (month !== undefined && month >= 0 && month <= 11) {
onSelectMonth(month);
}
}, [month]);
(0, _react.useEffect)(() => {
if (year !== undefined && year >= 0) {
onSelectYear(year);
}
}, [year]);
const memoizedStyles = (0, _utils.useDeepCompareMemo)({
...styles
}, [styles]);
const memoizedClassNames = (0, _utils.useDeepCompareMemo)({
...classNames
}, [classNames]);
const memoizedComponents = (0, _react.useMemo)(() => ({
...components
}), [components]);
const baseContextValue = (0, _react.useMemo)(() => ({
mode,
calendar,
locale,
numerals,
timeZone,
showOutsideDays,
timePicker,
minDate,
maxDate,
min,
max,
enabledDates,
disabledDates,
firstDayOfWeek: firstDay,
containerHeight,
weekdaysHeight,
navigationPosition,
weekdaysFormat,
monthsFormat,
monthCaptionFormat,
multiRangeMode,
hideHeader,
hideWeekdays,
disableMonthPicker,
disableYearPicker,
style,
className,
use12Hours
}), [mode, calendar, locale, numerals, timeZone, showOutsideDays, timePicker, minDate, maxDate, min, max, enabledDates, disabledDates, firstDay, containerHeight, weekdaysHeight, navigationPosition, weekdaysFormat, monthsFormat, monthCaptionFormat, multiRangeMode, hideHeader, hideWeekdays, disableMonthPicker, disableYearPicker, style, className, use12Hours]);
const handlerContextValue = (0, _react.useMemo)(() => ({
setCalendarView,
onSelectDate,
onSelectMonth,
onSelectYear,
onChangeMonth,
onChangeYear
}), [setCalendarView, onSelectDate, onSelectMonth, onSelectYear, onChangeMonth, onChangeYear]);
const styleContextValue = (0, _react.useMemo)(() => ({
classNames: memoizedClassNames,
styles: memoizedStyles
}), [memoizedClassNames, memoizedStyles]);
const memoizedValue = (0, _react.useMemo)(() => ({
...state,
...baseContextValue,
...handlerContextValue,
...styleContextValue,
components: memoizedComponents
}), [state, baseContextValue, handlerContextValue, styleContextValue, memoizedComponents]);
return /*#__PURE__*/_react.default.createElement(_calendarContext.CalendarContext.Provider, {
value: memoizedValue
}, /*#__PURE__*/_react.default.createElement(_calendar.default, null));
};
var _default = exports.default = DateTimePicker;
//# sourceMappingURL=datetime-picker.js.map