"use strict";

exports.__esModule = true;
exports.default = void 0;

var _react = _interopRequireWildcard(require("react"));

var _clsx = _interopRequireDefault(require("clsx"));

var _utils = require("../utils");

var _utils2 = require("./utils");

var _useRefs2 = _interopRequireDefault(require("../hooks/use-refs"));

var _raf = require("../utils/raf");

var _useRect = require("../hooks/use-rect");

var _toast = _interopRequireDefault(require("../toast"));

var _CalendarMonth = _interopRequireDefault(require("./CalendarMonth"));

var _button = _interopRequireDefault(require("../button"));

var _CalendarHeader = _interopRequireDefault(require("./CalendarHeader"));

var _popup = _interopRequireDefault(require("../popup"));

var _useSetState2 = _interopRequireDefault(require("../hooks/use-set-state"));

var _useUpdateEffect = _interopRequireDefault(require("../hooks/use-update-effect"));

var _ConfigProviderContext = _interopRequireDefault(require("../config-provider/ConfigProviderContext"));

var _excluded = ["className", "style"];

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

var Calendar = /*#__PURE__*/(0, _react.forwardRef)(function (_ref, ref) {
  var className = _ref.className,
      style = _ref.style,
      props = _objectWithoutPropertiesLoose(_ref, _excluded);

  var _useContext = (0, _react.useContext)(_ConfigProviderContext.default),
      prefixCls = _useContext.prefixCls,
      createNamespace = _useContext.createNamespace,
      locale = _useContext.locale;

  var _createNamespace = createNamespace('calendar', prefixCls),
      bem = _createNamespace[0];

  var limitDateRange = function limitDateRange(date, minDate, maxDate) {
    if (minDate === void 0) {
      minDate = props.minDate;
    }

    if (maxDate === void 0) {
      maxDate = props.maxDate;
    }

    if ((0, _utils2.compareDay)(date, minDate) === -1) {
      return minDate;
    }

    if ((0, _utils2.compareDay)(date, maxDate) === 1) {
      return maxDate;
    }

    return date;
  };

  var getInitialDate = function getInitialDate(defaultDate) {
    if (defaultDate === void 0) {
      defaultDate = props.defaultDate;
    }

    var type = props.type,
        minDate = props.minDate,
        maxDate = props.maxDate;

    if (defaultDate === null) {
      return defaultDate;
    }

    var now = (0, _utils2.getToday)();

    if (type === 'range') {
      if (!Array.isArray(defaultDate)) {
        defaultDate = [];
      }

      var start = limitDateRange(defaultDate[0] || now, minDate, (0, _utils2.getPrevDay)(maxDate));
      var end = limitDateRange(defaultDate[1] || now, (0, _utils2.getNextDay)(minDate));
      return [start, end];
    }

    if (type === 'multiple') {
      if (Array.isArray(defaultDate)) {
        return defaultDate.map(function (date) {
          return limitDateRange(date);
        });
      }

      return [limitDateRange(now)];
    }

    if (!defaultDate || Array.isArray(defaultDate)) {
      defaultDate = now;
    }

    return limitDateRange(defaultDate);
  };

  var bodyRef = (0, _react.useRef)();
  var bodyHeightRef = (0, _react.useRef)(0);

  var _useSetState = (0, _useSetState2.default)({
    subtitle: '',
    currentDate: getInitialDate()
  }),
      state = _useSetState[0],
      updateState = _useSetState[1];

  var _useRefs = (0, _useRefs2.default)(),
      monthRefs = _useRefs[0],
      setMonthRefs = _useRefs[1];

  var dayOffset = (0, _react.useMemo)(function () {
    return props.firstDayOfWeek ? +props.firstDayOfWeek % 7 : 0;
  }, [props.firstDayOfWeek, props.firstDayOfWeek]);
  var months = (0, _react.useMemo)(function () {
    var internalMonths = [];
    var cursor = new Date(props.minDate);
    cursor.setDate(1);

    do {
      internalMonths.push(new Date(cursor));
      cursor.setMonth(cursor.getMonth() + 1);
    } while ((0, _utils2.compareMonth)(cursor, props.maxDate) !== 1);

    return internalMonths;
  }, [props.minDate, props.maxDate]);
  var buttonDisabled = (0, _react.useMemo)(function () {
    var currentDate = state.currentDate;

    if (currentDate) {
      if (props.type === 'range') {
        return !currentDate[0] || !currentDate[1];
      }

      if (props.type === 'multiple') {
        return !currentDate.length;
      }
    }

    return !currentDate;
  }, [props.type, state.currentDate]); // calculate the position of the elements
  // and find the elements that needs to be rendered

  var onScroll = function onScroll() {
    var top = (0, _utils.getScrollTop)(bodyRef.current);
    var bottom = top + bodyHeightRef.current;
    var heights = months.map(function (item, index) {
      return monthRefs[index].getHeight();
    });
    var heightSum = heights.reduce(function (a, b) {
      return a + b;
    }, 0); // iOS scroll bounce may exceed the range

    if (bottom > heightSum && top > 0) {
      return;
    }

    var height = 0;
    var currentMonth;
    var visibleRange = [-1, -1];

    for (var i = 0; i < months.length; i++) {
      var month = monthRefs[i];
      var visible = height <= bottom && height + heights[i] >= top;

      if (visible) {
        visibleRange[1] = i;

        if (!currentMonth) {
          currentMonth = month;
          visibleRange[0] = i;
        }

        if (!monthRefs[i].showed) {
          monthRefs[i].showed = true;
          props.onMonthShow == null ? void 0 : props.onMonthShow({
            date: month.date,
            title: month.getTitle()
          });
        }
      }

      height += heights[i];
    }

    months.forEach(function (_, index) {
      var visible = index >= visibleRange[0] - 1 && index <= visibleRange[1] + 1;
      monthRefs[index].setVisible(visible);
    });
    /* istanbul ignore else */

    if (currentMonth) {
      updateState({
        subtitle: currentMonth.getTitle()
      });
    }
  };

  var scrollToDate = function scrollToDate(targetDate) {
    (0, _raf.raf)(function () {
      months.some(function (month, index) {
        if ((0, _utils2.compareMonth)(month, targetDate) === 0) {
          if (bodyRef.current) {
            monthRefs[index].scrollIntoView(bodyRef.current);
          }

          return true;
        }

        return false;
      });
      onScroll();
    });
  }; // scroll to current month


  var scrollIntoView = function scrollIntoView() {
    if (props.poppable && !props.visible) {
      return;
    }

    var currentDate = state.currentDate;

    if (currentDate) {
      var targetDate = props.type === 'single' ? currentDate : currentDate[0];
      scrollToDate(targetDate);
    } else {
      (0, _raf.raf)(onScroll);
    }
  };

  var init = function init() {
    if (props.poppable && !props.visible) {
      return;
    }

    (0, _raf.raf)(function () {
      // add Math.floor to avoid decimal height issues
      // https://github.com/youzan/vant/issues/5640
      bodyHeightRef.current = Math.floor((0, _useRect.getRect)(bodyRef.current).height);
      scrollIntoView();
    });
  };

  var reset = function reset(date) {
    if (date === void 0) {
      date = getInitialDate();
    }

    updateState({
      currentDate: date
    });
    scrollIntoView();
  };

  var checkRange = function checkRange(date) {
    var maxRange = props.maxRange,
        rangePrompt = props.rangePrompt,
        showRangePrompt = props.showRangePrompt;

    if (maxRange && (0, _utils2.calcDateNum)(date) > maxRange) {
      if (showRangePrompt) {
        _toast.default.info(rangePrompt || locale.vanCalendar.rangePrompt(+maxRange));
      }

      props.onOverRange == null ? void 0 : props.onOverRange();
      return false;
    }

    return true;
  };

  var onConfirm = function onConfirm() {
    props.onConfirm == null ? void 0 : props.onConfirm((0, _utils2.cloneDates)(state.currentDate));
  };

  var select = function select(date, complete) {
    var setCurrentDate = function setCurrentDate(current) {
      state.currentDate = current;
      updateState({
        currentDate: current
      });
      props.onSelect == null ? void 0 : props.onSelect((0, _utils2.cloneDates)(state.currentDate));
    };

    if (complete && props.type === 'range') {
      var valid = checkRange(date);

      if (!valid) {
        // auto selected to max range if showConfirm
        if (props.showConfirm) {
          setCurrentDate([date[0], (0, _utils2.getDayByOffset)(date[0], +props.maxRange - 1)]);
        } else {
          setCurrentDate(date);
        }

        return;
      }
    }

    setCurrentDate(date);

    if (complete && !props.showConfirm) {
      onConfirm();
    }
  };

  var onClickDay = function onClickDay(item) {
    if (props.readonly || !item.date) {
      return;
    }

    var date = item.date;
    var type = props.type;
    var currentDate = state.currentDate;

    if (type === 'range') {
      if (!currentDate) {
        select([date]);
        return;
      }

      var startDay = currentDate[0],
          endDay = currentDate[1];

      if (startDay && !endDay) {
        var compareToStart = (0, _utils2.compareDay)(date, startDay);

        if (compareToStart === 1) {
          select([startDay, date], true);
        } else if (compareToStart === -1) {
          select([date]);
        } else if (props.allowSameDay) {
          select([date, date], true);
        }
      } else {
        select([date]);
      }
    } else if (type === 'multiple') {
      if (!currentDate) {
        select([date]);
        return;
      }

      var selectedIndex;
      var selected = state.currentDate.some(function (dateItem, index) {
        var equal = (0, _utils2.compareDay)(dateItem, date) === 0;

        if (equal) {
          selectedIndex = index;
        }

        return equal;
      });

      if (selected) {
        var _currentDate$splice = currentDate.splice(selectedIndex, 1),
            unselectedDate = _currentDate$splice[0];

        props.onUnselect == null ? void 0 : props.onUnselect((0, _utils2.cloneDate)(unselectedDate));
        select([].concat(currentDate));
      } else if (props.maxRange && currentDate.length >= props.maxRange) {
        (0, _toast.default)(props.rangePrompt || "\u9009\u62E9\u5929\u6570\u4E0D\u80FD\u8D85\u8FC7 " + props.maxRange + " \u5929");
      } else {
        select([].concat(currentDate, [date]));
      }
    } else {
      select(date, true);
    }
  };

  var renderMonth = function renderMonth(date, index) {
    var showMonthTitle = index !== 0 || !props.showSubtitle;
    return /*#__PURE__*/_react.default.createElement(_CalendarMonth.default, _extends({
      key: index,
      ref: setMonthRefs(index),
      date: date,
      currentDate: state.currentDate,
      showMonthTitle: showMonthTitle,
      firstDayOfWeek: dayOffset
    }, (0, _utils.pick)(props, ['type', 'color', 'minDate', 'maxDate', 'showMark', 'formatter', 'rowHeight', 'showSubtitle', 'lazyRender', 'allowSameDay', 'topInfoRender', 'bottomInfoRender', 'formatMonthTitle']), {
      onClick: onClickDay
    }));
  };

  var renderFooterButton = function renderFooterButton() {
    if (props.footer) {
      return props.footer;
    }

    if (props.showConfirm) {
      var text = buttonDisabled ? props.confirmDisabledText : props.confirmText;
      return /*#__PURE__*/_react.default.createElement(_button.default, {
        round: true,
        block: true,
        type: "danger",
        color: props.color,
        className: (0, _clsx.default)(bem('confirm')),
        disabled: buttonDisabled,
        nativeType: "button",
        onClick: onConfirm
      }, text || locale.vanCalendar.confirm);
    }

    return null;
  };

  var renderFooter = function renderFooter() {
    return /*#__PURE__*/_react.default.createElement("div", {
      className: (0, _clsx.default)(bem('footer'), {
        'rv-safe-area-bottom': props.safeAreaInsetBottom
      })
    }, renderFooterButton());
  };

  var renderCalendar = function renderCalendar() {
    return /*#__PURE__*/_react.default.createElement("div", {
      className: (0, _clsx.default)(className, bem()),
      style: style
    }, /*#__PURE__*/_react.default.createElement(_CalendarHeader.default, {
      weekdays: props.weekdays,
      title: props.title,
      subtitle: props.subtitle || state.subtitle,
      showTitle: props.showTitle,
      showSubtitle: props.showSubtitle,
      firstDayOfWeek: dayOffset,
      "onClick-subtitle": function onClickSubtitle(event) {
        props.onClickSubtitle == null ? void 0 : props.onClickSubtitle(event);
      }
    }), /*#__PURE__*/_react.default.createElement("div", {
      ref: bodyRef,
      className: (0, _clsx.default)(bem('body')),
      onScroll: onScroll
    }, months.map(renderMonth)), renderFooter());
  };

  (0, _react.useEffect)(function () {
    init();
  }, [props.visible]);
  (0, _useUpdateEffect.default)(function () {
    reset(getInitialDate(state.currentDate));
  }, [props.type, props.minDate, props.maxDate]);
  (0, _useUpdateEffect.default)(function () {
    updateState({
      currentDate: props.defaultDate
    });
    scrollIntoView();
  }, [props.defaultDate]);
  (0, _react.useImperativeHandle)(ref, function () {
    return {
      reset: reset,
      scrollToDate: scrollToDate
    };
  });

  if (props.poppable) {
    return /*#__PURE__*/_react.default.createElement(_popup.default, {
      visible: props.visible,
      className: (0, _clsx.default)(bem('popup')),
      round: props.round,
      position: props.position,
      closeable: props.showTitle || props.showSubtitle,
      closeOnPopstate: props.closeOnPopstate,
      closeOnClickOverlay: props.closeOnClickOverlay,
      onClose: props.onClose,
      onClosed: props.onClosed
    }, renderCalendar());
  }

  return renderCalendar();
});
Calendar.defaultProps = {
  round: true,
  poppable: true,
  showMark: true,
  showTitle: true,
  showConfirm: true,
  showSubtitle: true,
  lazyRender: true,
  closeOnPopstate: true,
  closeOnClickOverlay: true,
  safeAreaInsetBottom: true,
  type: 'single',
  position: 'bottom',
  maxRange: null,
  minDate: (0, _utils2.getToday)(),
  maxDate: function () {
    var now = (0, _utils2.getToday)();
    return new Date(now.getFullYear(), now.getMonth() + 6, now.getDate());
  }(),
  firstDayOfWeek: 0,
  showRangePrompt: true
};
var _default = Calendar;
exports.default = _default;