'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

const index = require('./index-e1b469cd.js');
const index$1 = require('./index-067a58c1.js');

function getTimeRange(begin, end) {
  const range = [];
  for (let i = begin; i <= end; i++) {
    range.push(`${i < 10 ? '0' : ''}${i}`);
  }
  return range;
}
const hoursRange = [
  '20',
  '21',
  '22',
  '23',
  ...getTimeRange(0, 23),
  '00',
  '01',
  '02',
  '03'
];
const minutesRange = [
  '56',
  '57',
  '58',
  '59',
  ...getTimeRange(0, 59),
  '00',
  '01',
  '02',
  '03'
];
/**
 * 校验传入的 value 是否合法
 */
function verifyValue(value, range) {
  if (!isNaN(+value) && value >= 0 && value < range.length)
    return true;
  return false;
}
/**
 * 检验传入的 time value 是否合法
 */
function verifyTime(value) {
  if (!/^\d{1,2}:\d{1,2}$/.test(value))
    return false;
  const time = value.split(':').map(num => +num);
  if (time[0] < 0 || time[0] > 23)
    return false;
  if (time[1] < 0 || time[1] > 59)
    return false;
  return true;
}
/**
 * 比较时间
 * return t1 <= t2
 */
function compareTime(t1, t2) {
  const t1List = t1.split(':').map(i => +i);
  const t2List = t2.split(':').map(i => +i);
  if (t1List[0] < t2List[0])
    return true;
  if (t1List[0] === t2List[0] && t1List[1] <= t2List[1])
    return true;
  return false;
}
/**
 * 校验日期合法性，返回合法性和日期数组
 */
function verifyDate(dateStr) {
  if (!dateStr)
    return false;
  const date = new Date(dateStr.replace(/-/g, '/'));
  return isNaN(date.getMonth()) ? false : date;
}
/**
 * 获取当月最大天数
 */
function getMaxDay(year, month) {
  if (month === 4 || month === 6 || month === 9 || month === 11)
    return 30;
  if (month === 2) {
    if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0)
      return 29;
    else
      return 28;
  }
  return 31;
}
function formatValue(value) {
  let res;
  if (Array.isArray(value)) {
    res = value.map(item => String(item));
  }
  else {
    res = value;
  }
  return res;
}
/**
 * 获取时间数组
 */
function getDateRange(start, end) {
  const range = [];
  for (let i = start; i <= end; i++) {
    range.push(i);
  }
  return range;
}
/**
 * 获取年份区间数组
 */
function getYearRange(start, end) {
  return getDateRange(start, end);
}
/**
 * 获取月份区间数组
 */
function getMonthRange(start, end, year) {
  let rangeStart = 1;
  let rangeEnd = 12;
  // 当前年份等于开始年份，由开始对应的月份约束开始值
  if (start.getFullYear() === year) {
    rangeStart = start.getMonth() + 1;
  }
  // 当前年份等于结束年份，由结束对应的月份约束结束值
  if (end.getFullYear() === year) {
    rangeEnd = end.getMonth() + 1;
  }
  return getDateRange(rangeStart, rangeEnd);
}
/**
 * 获取日期区间数组
 */
function getDayRange(start, end, year, month) {
  let rangeStart = 1;
  let rangeEnd = getMaxDay(year, month);
  if (start.getFullYear() === year && start.getMonth() + 1 === month) {
    rangeStart = start.getDate();
  }
  if (end.getFullYear() === year && end.getMonth() + 1 === month) {
    rangeEnd = end.getDate();
  }
  return getDateRange(rangeStart, rangeEnd);
}

const TOP = 102;
const LINE_HEIGHT = 34;
const MASK_HEIGHT = LINE_HEIGHT * 7;

const indexCss = ".weui-picker,.weui-picker__hd{font-size:12px}";

const Picker = class {
  constructor(hostRef) {
    index.registerInstance(this, hostRef);
    this.onChange = index.createEvent(this, "change", 7);
    this.onColumnChange = index.createEvent(this, "columnchange", 7);
    this.onCancel = index.createEvent(this, "cancel", 7);
    this.index = [];
    // 展示 Picker
    this.showPicker = () => {
      if (this.disabled)
        return;
      this.height = this.getHeightByIndex();
      this.hidden = false;
    };
    this.getHeightByIndex = () => {
      const height = this.index.map(i => {
        let factor = 0;
        if (this.mode === 'time') {
          factor = LINE_HEIGHT * 4;
        }
        return TOP - LINE_HEIGHT * i - factor;
      });
      return height;
    };
    // 隐藏 picker
    this.hidePicker = () => {
      this.fadeOut = true;
      setTimeout(() => {
        this.hidden = true;
        this.fadeOut = false;
      }, 350);
    };
    // 点击确定按钮
    this.handleChange = () => {
      this.hidePicker();
      this.index = this.height.map(h => (TOP - h) / LINE_HEIGHT);
      let value = this.index.length && this.mode !== 'selector'
        ? this.index
        : this.index[0];
      if (this.mode === 'time') {
        const range = [hoursRange.slice(), minutesRange.slice()];
        const timeArr = this.index.map((n, i) => range[i][n]);
        this.index = timeArr.map(item => parseInt(item));
        value = timeArr.join(':');
      }
      if (this.mode === 'date') {
        const { _start, _end, _updateValue } = this.pickerDate;
        const currentYear = _updateValue[0];
        const currentMonth = _updateValue[1];
        const yearRange = getYearRange(_start.getFullYear(), _end.getFullYear());
        const monthRange = getMonthRange(_start, _end, currentYear);
        const dayRange = getDayRange(_start, _end, currentYear, currentMonth);
        const year = yearRange[this.index[0]];
        const month = monthRange[this.index[1]];
        const day = dayRange[this.index[2]];
        if (this.fields === 'year') {
          value = [year];
        }
        else if (this.fields === 'month') {
          value = [year, month];
        }
        else {
          value = [year, month, day];
        }
        value = value
          .map(item => {
          return item < 10 ? `0${item}` : item;
        })
          .join('-');
      }
      this.pickerValue = value;
      this.onChange.emit({
        value
      });
    };
    // 点击取消按钮或蒙层
    this.handleCancel = () => {
      this.hidePicker();
      this.onCancel.emit();
    };
    this.updateHeight = (height, columnId, needRevise = false) => {
      const temp = [...this.height];
      temp[columnId] = height;
      this.height = temp;
      // time picker 必须在规定时间范围内，因此需要在 touchEnd 做修正
      if (needRevise) {
        let { start, end } = this;
        if (!verifyTime(start))
          start = '00:00';
        if (!verifyTime(end))
          end = '23:59';
        if (!compareTime(start, end))
          return;
        const range = [hoursRange.slice(), minutesRange.slice()];
        const timeList = this.height.map(h => (TOP - h) / LINE_HEIGHT);
        const timeStr = timeList.map((n, i) => range[i][n]).join(':');
        if (!compareTime(start, timeStr)) {
          // 修正到 start
          const height = start
            .split(':')
            .map(i => TOP - LINE_HEIGHT * (+i + 4));
          requestAnimationFrame(() => (this.height = height));
        }
        else if (!compareTime(timeStr, end)) {
          // 修正到 end
          const height = end
            .split(':')
            .map(i => TOP - LINE_HEIGHT * (+i + 4));
          requestAnimationFrame(() => (this.height = height));
        }
      }
    };
    this.handleColumnChange = (height, columnId) => {
      this.onColumnChange.emit({
        column: Number(columnId),
        value: (TOP - height) / LINE_HEIGHT
      });
    };
    this.updateDay = (value, fields) => {
      const { _start, _end, _updateValue } = this.pickerDate;
      _updateValue[fields] = value;
      const currentYear = _updateValue[0];
      const currentMonth = _updateValue[1];
      const currentDay = _updateValue[2];
      // 滚动年份
      if (fields === 0) {
        const monthRange = getMonthRange(_start, _end, currentYear);
        const max = monthRange[monthRange.length - 1];
        const min = monthRange[0];
        if (currentMonth > max)
          _updateValue[1] = max;
        if (currentMonth < min)
          _updateValue[1] = min;
        const index = monthRange.indexOf(_updateValue[1]);
        const height = TOP - LINE_HEIGHT * index;
        this.updateDay(_updateValue[1], 1);
        this.updateHeight(height, '1');
      }
      else if (fields === 1) {
        const dayRange = getDayRange(_start, _end, currentYear, currentMonth);
        const max = dayRange[dayRange.length - 1];
        const min = dayRange[0];
        if (currentDay > max)
          _updateValue[2] = max;
        if (currentDay < min)
          _updateValue[2] = min;
        const index = dayRange.indexOf(_updateValue[2]);
        const height = TOP - LINE_HEIGHT * index;
        this.updateDay(_updateValue[2], 2);
        this.updateHeight(height, '2');
      }
    };
    // 单列选择器
    this.getSelector = () => {
      return (index.h("taro-picker-group", { range: this.range, rangeKey: this.rangeKey, height: this.height[0], updateHeight: this.updateHeight, columnId: '0' }));
    };
    // 多列选择器
    this.getMultiSelector = () => {
      return this.range.map((range, index$1) => {
        return (index.h("taro-picker-group", { range: range, rangeKey: this.rangeKey, height: this.height[index$1], updateHeight: this.updateHeight, onColumnChange: this.handleColumnChange, columnId: String(index$1) }));
      });
    };
    // 时间选择器
    this.getTimeSelector = () => {
      const hourRange = hoursRange.slice();
      const minRange = minutesRange.slice();
      return [
        index.h("taro-picker-group", { mode: 'time', range: hourRange, height: this.height[0], updateHeight: this.updateHeight, columnId: '0' }),
        index.h("taro-picker-group", { mode: 'time', range: minRange, height: this.height[1], updateHeight: this.updateHeight, columnId: '1' })
      ];
    };
    // 日期选择器
    this.getDateSelector = () => {
      const { fields, height } = this;
      const { _start, _end, _updateValue } = this.pickerDate;
      const currentYear = _updateValue[0];
      const currentMonth = _updateValue[1];
      const yearRange = getYearRange(_start.getFullYear(), _end.getFullYear())
        .map(item => `${item}年`);
      const monthRange = getMonthRange(_start, _end, currentYear)
        .map(item => `${item < 10 ? `0${item}` : item}月`);
      const dayRange = getDayRange(_start, _end, currentYear, currentMonth)
        .map(item => `${item < 10 ? `0${item}` : item}日`);
      const renderView = [
        index.h("taro-picker-group", { mode: 'date', range: yearRange, height: height[0], updateDay: this.updateDay, updateHeight: this.updateHeight, columnId: '0' })
      ];
      if (fields === 'month' || fields === 'day') {
        renderView.push(index.h("taro-picker-group", { mode: 'date', range: monthRange, height: height[1], updateDay: this.updateDay, updateHeight: this.updateHeight, columnId: '1' }));
      }
      if (fields === 'day') {
        renderView.push(index.h("taro-picker-group", { mode: 'date', range: dayRange, height: height[2], updateDay: this.updateDay, updateHeight: this.updateHeight, columnId: '2' }));
      }
      return renderView;
    };
    this.mode = 'selector';
    this.disabled = false;
    this.range = [];
    this.rangeKey = undefined;
    this.value = undefined;
    this.start = '';
    this.end = '';
    this.fields = 'day';
    this.name = '';
    this.pickerValue = [];
    this.height = [];
    this.hidden = true;
    this.fadeOut = false;
    this.isWillLoadCalled = false;
  }
  componentWillLoad() {
    this.isWillLoadCalled = true;
    this.handleProps();
  }
  componentDidLoad() {
    Object.defineProperty(this.el, 'value', {
      get: () => this.pickerValue,
      set: val => (this.value = val),
      configurable: true
    });
    if (this.overlay) {
      document.body.appendChild(this.overlay);
    }
  }
  disconnectedCallback() {
    var _a;
    if (this.overlay) {
      (_a = this.overlay.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this.overlay);
    }
  }
  onPropsChange() {
    if (!this.isWillLoadCalled)
      return;
    this.handleProps();
  }
  handleProps() {
    const { mode, start, end } = this;
    if (mode === 'selector') {
      const value = this.value;
      this.index = [verifyValue(value, this.range) ? Math.floor(value) : 0];
    }
    else if (mode === 'multiSelector') {
      const value = this.value;
      this.index = [];
      this.range.forEach((range, index) => {
        const val = value === null || value === void 0 ? void 0 : value[index];
        const item = verifyValue(val, range) ? Math.floor(val) : 0;
        this.index.push(item);
      });
    }
    else if (mode === 'time') {
      let value = this.value;
      // check value...
      if (!verifyTime(value)) {
        console.warn('time picker value illegal');
        value = '0:0';
      }
      const time = value.split(':').map(n => +n);
      this.index = time;
    }
    else if (mode === 'date') {
      const value = this.value;
      const _value = verifyDate(value) || new Date(new Date().setHours(0, 0, 0, 0)); // 没传值或值的合法性错误默认今天时间
      const _start = verifyDate(start) || new Date('1970/01/01');
      const _end = verifyDate(end) || new Date('2999/01/01');
      // 时间区间有效性
      if (_value >= _start && _value <= _end) {
        const currentYear = _value.getFullYear();
        const currentMonth = _value.getMonth() + 1;
        const currentDay = _value.getDate();
        const yearRange = getYearRange(_start.getFullYear(), _end.getFullYear());
        const monthRange = getMonthRange(_start, _end, currentYear);
        const dayRange = getDayRange(_start, _end, currentYear, currentMonth);
        this.index = [
          yearRange.indexOf(currentYear),
          monthRange.indexOf(currentMonth),
          dayRange.indexOf(currentDay)
        ];
        if (!this.pickerDate ||
          this.pickerDate._value.getTime() !== _value.getTime() ||
          this.pickerDate._start.getTime() !== _start.getTime() ||
          this.pickerDate._end.getTime() !== _end.getTime()) {
          this.pickerDate = {
            _value,
            _start,
            _end,
            _updateValue: [
              currentYear,
              currentMonth,
              currentDay
            ]
          };
        }
      }
      else {
        throw new Error('Date Interval Error');
      }
    }
    // Prop 变化时，无论是否正在显示弹层，都更新 height 值
    this.height = this.getHeightByIndex();
    // 同步表单 value 值，用于 form submit
    this.pickerValue = this.value;
    if (mode === 'date') {
      const val = this.pickerValue;
      if (this.fields === 'month') {
        this.pickerValue = val.split('-').slice(0, 2).join('-');
      }
      else if (this.fields === 'year') {
        this.pickerValue = val.split('-')[0];
      }
    }
  }
  render() {
    const { name, mode, fadeOut, hidden } = this;
    // 选项条
    let pickerGroup;
    switch (mode) {
      case 'multiSelector':
        pickerGroup = this.getMultiSelector();
        break;
      case 'time':
        pickerGroup = this.getTimeSelector();
        break;
      case 'date':
        pickerGroup = this.getDateSelector();
        break;
      default:
        pickerGroup = this.getSelector();
    }
    // 动画类名控制逻辑
    const clsMask = index$1.classnames('weui-mask', 'weui-animate-fade-in', {
      'weui-animate-fade-out': fadeOut
    });
    const clsSlider = index$1.classnames('weui-picker', 'weui-animate-slide-up', {
      'weui-animate-slide-down': fadeOut
    });
    const shouldDivHidden = hidden ? { display: 'none' } : {};
    return (index.h(index.Host, null, index.h("div", { onClick: this.showPicker }, index.h("slot", null), index.h("input", { type: 'hidden', name: name, value: formatValue(this.pickerValue) })), index.h("div", { class: 'weui-picker__overlay', style: shouldDivHidden, ref: el => { this.overlay = el; } }, index.h("div", { class: clsMask, onClick: this.handleCancel }), index.h("div", { class: clsSlider }, index.h("div", { class: 'weui-picker__hd' }, index.h("div", { class: 'weui-picker__action', onClick: this.handleCancel }, "\u53D6\u6D88"), index.h("div", { class: 'weui-picker__action', onClick: this.handleChange }, "\u786E\u5B9A")), index.h("div", { class: 'weui-picker__bd' }, pickerGroup), index.h("input", { type: 'hidden', name: name, value: formatValue(this.pickerValue) })))));
  }
  get el() { return index.getElement(this); }
  static get watchers() { return {
    "mode": ["onPropsChange"],
    "value": ["onPropsChange"],
    "range": ["onPropsChange"],
    "start": ["onPropsChange"],
    "end": ["onPropsChange"]
  }; }
};
Picker.style = indexCss;

const TaroPickerGroup = class {
  constructor(hostRef) {
    index.registerInstance(this, hostRef);
    this.mode = undefined;
    this.range = [];
    this.rangeKey = undefined;
    this.height = undefined;
    this.columnId = undefined;
    this.updateHeight = undefined;
    this.onColumnChange = undefined;
    this.updateDay = undefined;
    this.startY = undefined;
    this.preY = undefined;
    this.hadMove = undefined;
    this.touchEnd = undefined;
    this.isMove = undefined;
  }
  getPosition() {
    const transition = this.touchEnd ? 0.3 : 0;
    const transformValue = `translate3d(0, ${this.height}px, 0)`;
    const transitionValue = `transform ${transition}s`;
    return {
      transform: transformValue,
      '-webkit-transform': transformValue,
      transition: transitionValue,
      '-webkit-transition': transitionValue
    };
  }
  formulaUnlimitedScroll(range, absoluteHeight, direction) {
    const { height, updateHeight, columnId } = this;
    const factor = direction === 'up' ? 1 : -1;
    this.touchEnd = false;
    // 点击超过范围，点击到补帧时，先跳到另一端的补帧
    updateHeight(-range * factor * LINE_HEIGHT + height, columnId);
    // 再做过渡动画
    requestAnimationFrame(() => {
      this.touchEnd = true;
      const index = Math.round(absoluteHeight / -LINE_HEIGHT) + range * factor;
      const relativeHeight = TOP - LINE_HEIGHT * index;
      updateHeight(relativeHeight, columnId, true);
    });
  }
  handleMoveStart(clientY) {
    // 记录第一次的点击位置
    this.startY = clientY;
    this.preY = clientY;
    this.hadMove = false;
  }
  handleMoving(clientY) {
    const y = clientY;
    const deltaY = y - this.preY;
    this.preY = y;
    this.touchEnd = false;
    if (Math.abs(y - this.startY) > 10)
      this.hadMove = true;
    let newPos = this.height + deltaY;
    // 处理时间选择器的无限滚动
    if (this.mode === 'time') {
      if (this.columnId === '0') {
        // 数字 28 来自于 4 格补帧 + 0 ～ 23 的 24 格，共 28 格
        if (newPos > TOP - LINE_HEIGHT * 3) {
          newPos = TOP - LINE_HEIGHT * 27 + deltaY;
        }
        if (newPos < TOP - LINE_HEIGHT * 28) {
          newPos = TOP - LINE_HEIGHT * 4 + deltaY;
        }
      }
      else if (this.columnId === '1') {
        if (newPos > TOP - LINE_HEIGHT * 3) {
          newPos = TOP - LINE_HEIGHT * 63 + deltaY;
        }
        if (newPos < TOP - LINE_HEIGHT * 64) {
          newPos = TOP - LINE_HEIGHT * 4 + deltaY;
        }
      }
    }
    this.updateHeight(newPos, this.columnId);
  }
  handleMoveEnd(clientY) {
    const { mode, range, height, updateHeight, onColumnChange, columnId } = this;
    const max = 0;
    const min = -LINE_HEIGHT * (range.length - 1);
    const endY = clientY;
    this.touchEnd = true;
    // touchEnd 时的高度，可能带小数点，需要再处理
    let absoluteHeight;
    if (!this.hadMove) {
      /** 点击 */
      // 屏幕高度
      const windowHeight = window.innerHeight;
      // picker__mask 垂直方向距离屏幕顶部的高度
      const relativeY = windowHeight - MASK_HEIGHT / 2;
      absoluteHeight = height - TOP - (endY - relativeY);
      // 处理时间选择器的无限滚动
      if (mode === 'time') {
        if (columnId === '0') {
          // 点击上溢出
          // absoluteHeight 是相对模块中点来算的，所以会算多半行，这时要减去这半行，即2.5行
          if (absoluteHeight > -LINE_HEIGHT * 2.5) {
            return this.formulaUnlimitedScroll(24, absoluteHeight, 'up');
          }
          // 点击下溢出
          if (absoluteHeight < -LINE_HEIGHT * 28.5) {
            return this.formulaUnlimitedScroll(24, absoluteHeight, 'down');
          }
        }
        else if (columnId === '1') {
          // 点击上溢出
          if (absoluteHeight > -LINE_HEIGHT * 2.5) {
            return this.formulaUnlimitedScroll(60, absoluteHeight, 'up');
          }
          // 点击下溢出
          if (absoluteHeight < -LINE_HEIGHT * 64.5) {
            return this.formulaUnlimitedScroll(60, absoluteHeight, 'down');
          }
        }
      }
    }
    else {
      /** 滚动 */
      absoluteHeight = height - TOP;
    }
    // 边界情况处理
    if (absoluteHeight > max)
      absoluteHeight = 0;
    if (absoluteHeight < min)
      absoluteHeight = min;
    // 先按公式算出 index, 再用此 index 算出一个整数高度
    const index = Math.round(absoluteHeight / -LINE_HEIGHT);
    const relativeHeight = TOP - LINE_HEIGHT * index;
    if (this.mode === 'date') {
      if (this.columnId === '0') {
        this.updateDay(+this.range[index].replace(/[^0-9]/gi, ''), 0);
      }
      if (this.columnId === '1') {
        this.updateDay(+this.range[index].replace(/[^0-9]/gi, ''), 1);
      }
      if (this.columnId === '2') {
        this.updateDay(+this.range[index].replace(/[^0-9]/gi, ''), 2);
      }
    }
    updateHeight(relativeHeight, columnId, mode === 'time');
    onColumnChange && onColumnChange(relativeHeight, columnId);
  }
  onMouseDown(e) {
    this.isMove = true;
    this.handleMoveStart(e.clientY);
  }
  onMouseMove(e) {
    e.preventDefault();
    if (!this.isMove)
      return;
    this.handleMoving(e.clientY);
  }
  onMouseMoveEnd(e) {
    if (!this.isMove)
      return;
    this.isMove = false;
    this.handleMoveEnd(e.clientY);
  }
  onTouchStart(e) {
    this.handleMoveStart(e.changedTouches[0].clientY);
  }
  onTouchMove(e) {
    e.preventDefault();
    this.handleMoving(e.changedTouches[0].clientY);
  }
  onTouchEnd(e) {
    this.handleMoveEnd(e.changedTouches[0].clientY);
  }
  render() {
    const { range, rangeKey } = this;
    const pickerItem = range.map(item => {
      const content = rangeKey ? item[rangeKey] : item;
      return (index.h("div", { class: 'weui-picker__item' }, content));
    });
    return (index.h(index.Host, { class: 'weui-picker__group' }, index.h("div", { class: 'weui-picker__mask' }), index.h("div", { class: 'weui-picker__indicator' }), index.h("div", { class: 'weui-picker__content', style: this.getPosition() }, pickerItem)));
  }
};

exports.taro_picker_core = Picker;
exports.taro_picker_group = TaroPickerGroup;

//# sourceMappingURL=taro-picker-core_2.cjs.entry.js.map