@vnmfify/core
Version:
```shell npm i @vnmfify/core -S ```
450 lines (379 loc) • 13.6 kB
JavaScript
import _map from "lodash/map";
import _isArray from "lodash/isArray";
import _isDate from "lodash/isDate";
import _size from "lodash/size";
import _filter from "lodash/filter";
import _isFunction from "lodash/isFunction";
import _isBoolean from "lodash/isBoolean";
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
import { useUncontrolled } from "@vnmfify/hooks";
import { ScrollView, View } from "@vnxjs/components";
import { nextTick } from "@vnxjs/vnmf";
import classNames from "classnames";
import * as React from "react";
import { Children, isValidElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
import useMounted from "../hooks/use-mounted";
import { prefixClassname } from "../styles";
import { getRect } from "../utils/dom/rect";
import { getScrollTop } from "../utils/dom/scroll";
import { useRefs } from "../utils/state";
import CalendarFooter from "./calendar-footer";
import CalendarHeader from "./calendar-header";
import CalendarMonth from "./calendar-month";
import CalendarContext from "./calendar.context";
import { compareDate, compareYearMonth, createNextDay, createPreviousDay, createToday, MAX_DATE, MIN_DATE } from "./calendar.shared";
function defaultSubtitleRender(date) {
return "".concat(date.getMonth() + 1, "/").concat(date.getFullYear())
}
function useSubtitleRender(subtitle) {
var renderRef = useRef();
var getRender = useCallback(() => {
if (_isBoolean(subtitle) && subtitle) {
return defaultSubtitleRender;
} else if (_isBoolean(subtitle) && !subtitle) {
return () => undefined;
} else if (_isFunction(subtitle)) {
return subtitle;
}
return () => subtitle;
}, [subtitle]);
useEffect(() => {
renderRef.current = getRender();
}, [getRender, subtitle]);
return useCallback(date => {
var _renderRef$current;
return (_renderRef$current = renderRef.current) === null || _renderRef$current === void 0 ? void 0 : _renderRef$current.call(renderRef, date);
}, []);
}
function defaultFormatter(day) {
return day;
}
function useCalendarChildren(children) {
var __children__ = {};
Children.forEach(children, child => {
if ( /*#__PURE__*/isValidElement(child)) {
var element = child;
var {
type: elementType
} = element;
if (elementType === CalendarFooter) {
__children__.footer = element;
}
}
});
return __children__;
}
function Calendar(props) {
var {
className,
style,
title = true,
subtitle: subtitleProp = true,
type = "single",
defaultValue,
value: valueProp,
min: minValue = MIN_DATE,
max: maxValue = MAX_DATE,
firstDayOfWeek,
isVietNamese = false,
readonly = false,
watermark = true,
formatter = defaultFormatter,
children: childrenProp,
onChange: onChangeProp,
onConfirm
} = props;
var {
value,
setValue
} = useUncontrolled({
defaultValue,
value: valueProp,
onChange: onChangeProp
});
var {
footer
} = useCalendarChildren(childrenProp);
var bodyRef = useRef();
var hasConfirmRef = useRef(false);
var subtitleRender = useSubtitleRender(subtitleProp);
var [subtitle, setSubtitle] = useState();
var changeValueRef = useRef();
var [bodyScrollTop, setBodyScrollTop] = useState(0);
var bodyScrollTopRef = useRef(0);
var {
getRef: getMonthRef,
getRefs: getMonthRefs,
setRefs: setMonthRefs,
clearRefs: clearMonthRefs
} = useRefs();
var dayOffset = useMemo(() => firstDayOfWeek ? +firstDayOfWeek % 7 : 0, [firstDayOfWeek]);
var months = useMemo(() => {
var months = [];
var cursor = new Date(minValue);
cursor.setDate(1);
do {
months.push(new Date(cursor));
cursor.setMonth(cursor.getMonth() + 1);
} while (compareYearMonth(cursor, maxValue) !== 1);
return months;
}, [maxValue, minValue]);
function limitDateRange(date) {
var minDate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : minValue;
var maxDate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : maxValue;
if (compareDate(date, minDate) === -1) {
return minDate;
}
if (compareDate(date, maxDate) === 1) {
return maxDate;
}
return date;
}
function getInitialDate(defaultDate) {
if (defaultDate === null) {
return defaultDate;
}
var now = createToday();
if (type === "range") {
if (!Array.isArray(defaultDate)) {
defaultDate = [];
}
var start = limitDateRange(defaultDate[0] || now, minValue, createPreviousDay(maxValue));
var end = limitDateRange(defaultDate[1] || now, createNextDay(minValue));
return [start, end];
}
if (type === "multiple") {
if (Array.isArray(defaultDate)) {
return defaultDate.map(date => limitDateRange(date));
}
return [limitDateRange(now)];
}
if (!defaultDate || Array.isArray(defaultDate)) {
defaultDate = now;
}
return limitDateRange(defaultDate);
}
function getDisabledDate(disabledDays, startDay, date) {
var _disabledDays$find;
return (_disabledDays$find = disabledDays.find(day => compareDate(startDay, day.value) === -1 && compareDate(day.value, date) === -1)) === null || _disabledDays$find === void 0 ? void 0 : _disabledDays$find.value;
}
function getDisabledDays() {
return getMonthRefs().reduce((arr, ref) => {
var _ref$current$disabled, _ref$current;
arr.push(...((_ref$current$disabled = (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.disabledDays) !== null && _ref$current$disabled !== void 0 ? _ref$current$disabled : []));
return arr;
}, []);
}
function change(dateValue, complete) {
changeValueRef.current = dateValue;
setValue === null || setValue === void 0 ? void 0 : setValue(dateValue);
if (complete && !hasConfirmRef.current) {
onConfirm === null || onConfirm === void 0 ? void 0 : onConfirm(dateValue);
}
}
function onDayClick(day) {
var {
value: date
} = day;
if (readonly || !date) {
return;
}
if (type === "range") {
var disabledDays = getDisabledDays();
if (!value) {
change([date]);
return;
}
var [startDay, endDay] = value;
if (startDay && !endDay) {
var compareToStart = compareDate(date, startDay);
if (compareToStart === 1) {
var disabledDay = getDisabledDate(disabledDays, startDay, date);
if (disabledDay) {
change([startDay, createPreviousDay(disabledDay)]);
} else {
change([startDay, date], true);
}
} else if (compareToStart === -1) {
change([date]);
} else {
change([date, date], true);
}
} else {
change([date]);
}
} else if (type === "multiple") {
if (!value) {
change([date]);
return;
}
var dates = value;
var newDates = _filter(dates, dateItem => compareDate(dateItem, date) !== 0);
if (_size(newDates) !== _size(dates)) {
change(newDates);
} else {
change([...dates, date]);
}
} else {
change(date, true);
}
}
function _onScroll2() {
return _onScroll.apply(this, arguments);
}
function _onScroll() {
_onScroll = _asyncToGenerator(function* () {
var top = yield getScrollTop(bodyRef);
var bodyHeight = (yield getRect(bodyRef)).height;
var bottom = top + bodyHeight;
var heights = months.map((item, index) => getMonthRef(index).current.getHeight());
var heightSum = heights.reduce((a, b) => a + b, 0);
if (bottom > heightSum && top > 0) {
return;
}
var height = 0;
var currentMonth;
for (var i = 0; i < months.length; i++) {
var month = getMonthRef(i);
var visible = height <= bottom && height + heights[i] >= top;
if (visible && !currentMonth) {
currentMonth = month;
break;
}
height += heights[i];
}
if (currentMonth) {
var _subtitle = subtitleRender(currentMonth.current.getValue());
setMonthSubtitle(currentMonth.current, _subtitle);
}
});
return _onScroll.apply(this, arguments);
}
function setMonthSubtitle(currentMonth, subtitle) {
if (currentMonth) {
setSubtitle(subtitle);
}
}
function scrollToDate(_x) {
return _scrollToDate.apply(this, arguments);
}
function _scrollToDate() {
_scrollToDate = _asyncToGenerator(function* (targetDate) {
months.some((month, index) => {
if (compareYearMonth(month, targetDate) === 0) {
var currentMonth = getMonthRef(index).current;
var _subtitle2 = subtitleRender(currentMonth.getValue());
setMonthSubtitle(currentMonth, _subtitle2);
nextTick(() => {
if (bodyRef.current) {
Promise.all([getRect(bodyRef), getScrollTop(bodyRef), currentMonth === null || currentMonth === void 0 ? void 0 : currentMonth.getScrollTop(_subtitle2)]).then(_ref2 => {
var [{
top: bodyTop
}, bodyScrollTop, monthScrollTop] = _ref2;
var newBodyScrollTop = monthScrollTop - bodyTop + bodyScrollTop;
if (bodyScrollTopRef.current !== newBodyScrollTop) {
setBodyScrollTop(bodyScrollTopRef.current);
setBodyScrollTop(newBodyScrollTop);
} else {
setBodyScrollTop(newBodyScrollTop);
}
});
}
});
return true;
}
return false;
});
});
return _scrollToDate.apply(this, arguments);
}
function scrollIntoView(_x2) {
return _scrollIntoView.apply(this, arguments);
}
function _scrollIntoView() {
_scrollIntoView = _asyncToGenerator(function* (newValue) {
if (newValue) {
var targetDate = (() => {
if (type === "single" && _isDate(newValue)) {
return newValue;
} else if (_isArray(newValue)) {
return newValue[0];
}
})();
yield scrollToDate(targetDate);
} else {
yield _onScroll2();
}
});
return _scrollIntoView.apply(this, arguments);
}
var reset = date => nextTick(() => scrollIntoView(date).then());
var init = () => reset(value);
useEffect(() => {
if (value !== changeValueRef.current) {
reset(getInitialDate(value));
}
}, [value]);
useEffect(() => {
reset(getInitialDate(value));
}, [type, subtitleRender, minValue, maxValue]);
useMounted(init);
var monthsRender = useMemo(() => {
clearMonthRefs === null || clearMonthRefs === void 0 ? void 0 : clearMonthRefs();
return _map(months, (month, index) => /*#__PURE__*/React.createElement(CalendarMonth, {
ref: setMonthRefs(index),
key: month.getTime(),
value: month,
top: index === 0,
watermark: watermark
}));
}, [clearMonthRefs, months, setMonthRefs, watermark]);
function notifyConfirm(hasConfirm) {
hasConfirmRef.current = hasConfirm;
}
function handleConfirm() {
onConfirm === null || onConfirm === void 0 ? void 0 : onConfirm(value);
}
return /*#__PURE__*/React.createElement(CalendarContext.Provider, {
value: {
type,
subtitle,
firstDayOfWeek: dayOffset,
min: minValue,
max: maxValue,
value,
formatter,
onDayClick,
notifyConfirm,
onConfirm: handleConfirm
}
}, /*#__PURE__*/React.createElement(View, {
className: classNames(prefixClassname("calendar"), prefixClassname("calendar--".concat(type)), className),
style: style
}, (title || subtitle) && /*#__PURE__*/React.createElement(CalendarHeader, {
isVietNamese: isVietNamese,
title: title,
subtitle: subtitle
}), /*#__PURE__*/React.createElement(ScrollView, {
ref: bodyRef,
className: prefixClassname("calendar__body"),
scrollY: true,
scrollTop: bodyScrollTop,
onScroll: function () {
var _onScroll3 = _asyncToGenerator(function* (_ref) {
var {
detail
} = _ref;
bodyScrollTopRef.current = detail.scrollTop;
yield _onScroll2();
});
function onScroll(_x3) {
return _onScroll3.apply(this, arguments);
}
return onScroll;
}()
}, monthsRender), footer));
}
export default Calendar;
//# sourceMappingURL=calendar.js.map