{"version":3,"file":"basic-time-spinner.mjs","sources":["../../../../../../../packages/components/time-picker/src/time-picker-com/basic-time-spinner.vue"],"sourcesContent":["<template>\r\n  <div class=\"sg-time-spinner\" :class=\"{ 'has-seconds': showSeconds }\">\r\n    <template v-if=\"!arrowControl\">\r\n      <sg-scrollbar\r\n        v-for=\"item in spinnerItems\"\r\n        :key=\"item\"\r\n        :ref=\"(scollbar) => setRef(scollbar, item)\"\r\n        class=\"sg-time-spinner__wrapper\"\r\n        wrap-style=\"max-height: inherit;\"\r\n        view-class=\"sg-time-spinner__list\"\r\n        noresize\r\n        tag=\"ul\"\r\n        @mouseenter=\"emitSelectRange(item)\"\r\n        @mousemove=\"adjustCurrentSpinner(item)\"\r\n      >\r\n        <li\r\n          v-for=\"(disabled, key) in listMap[item].value\"\r\n          :key=\"key\"\r\n          class=\"sg-time-spinner__item\"\r\n          :class=\"{ active: key === timePartsMap[item].value, disabled }\"\r\n          @click=\"handleClick(item, { value: key, disabled })\"\r\n        >\r\n          <template v-if=\"item === 'hours'\">\r\n            {{ ('0' + (amPmMode ? key % 12 || 12 : key)).slice(-2)\r\n            }}{{ getAmPmFlag(key) }}\r\n          </template>\r\n          <template v-else>\r\n            {{ ('0' + key).slice(-2) }}\r\n          </template>\r\n        </li>\r\n      </sg-scrollbar>\r\n    </template>\r\n  </div>\r\n</template>\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, nextTick, computed, onMounted, watch } from 'vue'\r\nimport debounce from 'lodash/debounce'\r\nimport { RepeatClick } from '@sgui-plus/directives'\r\nimport SgScrollbar from '@sgui-plus/components/scrollbar'\r\nimport SgIcon from '@sgui-plus/components/icon'\r\nimport { getTimeLists } from './useTimePicker'\r\n\r\nimport type { PropType, Ref } from 'vue'\r\nimport type { Dayjs } from 'dayjs'\r\nimport type { Nullable } from '@sgui-plus/utils/types'\r\n\r\nexport default defineComponent({\r\n  directives: {\r\n    repeatClick: RepeatClick,\r\n  },\r\n\r\n  components: {\r\n    SgScrollbar,\r\n    SgIcon,\r\n  },\r\n\r\n  props: {\r\n    role: {\r\n      type: String,\r\n      required: true,\r\n    },\r\n    spinnerDate: {\r\n      type: Object as PropType<Dayjs>,\r\n      required: true,\r\n    },\r\n    arrowControl: {\r\n      type: Boolean,\r\n      default: false\r\n    },\r\n    showSeconds: {\r\n      type: Boolean,\r\n      default: true,\r\n    },\r\n    amPmMode: {\r\n      type: String,\r\n      default: '', // 'a': am/pm; 'A': AM/PM\r\n    },\r\n    disabledHours: {\r\n      type: Function,\r\n    },\r\n    disabledMinutes: {\r\n      type: Function,\r\n    },\r\n    disabledSeconds: {\r\n      type: Function,\r\n    },\r\n    step: {\r\n      type: Object,\r\n    },\r\n  },\r\n\r\n  emits: ['change', 'select-range', 'set-option'],\r\n\r\n  setup(props, ctx) {\r\n    // data\r\n    let isScrolling = false\r\n    const debouncedResetScroll = debounce((type) => {\r\n      isScrolling = false\r\n      adjustCurrentSpinner(type)\r\n    }, 200)\r\n    const currentScrollbar = ref(null)\r\n    const listHoursRef: Ref<Nullable<HTMLElement>> = ref(null)\r\n    const listMinutesRef: Ref<Nullable<HTMLElement>> = ref(null)\r\n    const listSecondsRef: Ref<Nullable<HTMLElement>> = ref(null)\r\n    const listRefsMap = {\r\n      hours: listHoursRef,\r\n      minutes: listMinutesRef,\r\n      seconds: listSecondsRef,\r\n    }\r\n\r\n    // computed\r\n    const spinnerItems = computed(() => {\r\n      const arr = ['hours', 'minutes', 'seconds']\r\n      return props.showSeconds ? arr : arr.slice(0, 2)\r\n    })\r\n    const hours = computed(() => {\r\n      return props.spinnerDate.hour()\r\n    })\r\n    const minutes = computed(() => {\r\n      return props.spinnerDate.minute()\r\n    })\r\n    const seconds = computed(() => {\r\n      return props.spinnerDate.second()\r\n    })\r\n    const timePartsMap = computed(() => ({\r\n      hours,\r\n      minutes,\r\n      seconds,\r\n    }))\r\n    const hoursList = computed(() => {\r\n      return getHoursList(props.role)\r\n    })\r\n    const minutesList = computed(() => {\r\n      return getMinutesList(hours.value, props.role)\r\n    })\r\n    const secondsList = computed(() => {\r\n      return getSecondsList(hours.value, minutes.value, props.role)\r\n    })\r\n    const listMap = computed(() => ({\r\n      hours: hoursList,\r\n      minutes: minutesList,\r\n      seconds: secondsList,\r\n    }))\r\n    const getAmPmFlag = (hour) => {\r\n      const shouldShowAmPm = !!props.amPmMode\r\n      if (!shouldShowAmPm) return ''\r\n      const isCapital = props.amPmMode === 'A'\r\n      // todo locale\r\n      let content = hour < 12 ? ' am' : ' pm'\r\n      if (isCapital) content = content.toUpperCase()\r\n      return content\r\n    }\r\n\r\n    const emitSelectRange = (type) => {\r\n      if (type === 'hours') {\r\n        ctx.emit('select-range', 0, 2)\r\n      } else if (type === 'minutes') {\r\n        ctx.emit('select-range', 3, 5)\r\n      } else if (type === 'seconds') {\r\n        ctx.emit('select-range', 6, 8)\r\n      }\r\n      currentScrollbar.value = type\r\n    }\r\n\r\n    const adjustCurrentSpinner = (type) => {\r\n      adjustSpinner(type, timePartsMap.value[type].value)\r\n    }\r\n\r\n    // NOTE: used by datetime / date-range panel\r\n    //       renamed from adjustScrollTop\r\n    //       should try to refactory it\r\n    const adjustSpinners = () => {\r\n      adjustCurrentSpinner('hours')\r\n      adjustCurrentSpinner('minutes')\r\n      adjustCurrentSpinner('seconds')\r\n    }\r\n\r\n    const adjustSpinner = (type, value) => {\r\n      const el = listRefsMap[type]\r\n      if (el && el.$el) {\r\n        el.$el.querySelector('.sg-scrollbar__wrap').scrollTop = Math.max(\r\n          0,\r\n          value * typeItemHeight(type)\r\n        )\r\n      }\r\n    }\r\n\r\n    const typeItemHeight = (type) => {\r\n      const el = listRefsMap[type]\r\n      return el.$el.querySelector('li').offsetHeight\r\n    }\r\n\r\n    const getStep = (step:number,item?) => {\r\n      if(props.step) {\r\n        const label = item ? item : currentScrollbar.value\r\n        let newStep = 0\r\n        if(step >= 0) newStep = props.step[label!] ? props.step[label!] : step\r\n        else newStep =props.step[label!] ? -props.step[label!] : step\r\n        return newStep\r\n      } else return step\r\n    }\r\n\r\n\r\n    const scrollDown = (step) => {\r\n      if (!currentScrollbar.value) {\r\n        emitSelectRange('hours')\r\n      }\r\n      const label = currentScrollbar.value\r\n      const newStep = getStep(step)\r\n      let now:number = timePartsMap.value[label!]['value']\r\n      const total = currentScrollbar.value === 'hours' ? 24 : 60\r\n      now = (now + newStep + total) % total\r\n\r\n      modifyDateField(label, now)\r\n      adjustSpinner(label, now)\r\n      nextTick(() => emitSelectRange(currentScrollbar.value))\r\n    }\r\n\r\n    const modifyDateField = (type, value) => {\r\n      const list = listMap.value[type].value\r\n      const isDisabled = list[value]\r\n      if (isDisabled) return\r\n      switch (type) {\r\n        case 'hours':\r\n          ctx.emit(\r\n            'change',\r\n            props.spinnerDate\r\n              .hour(value)\r\n              .minute(minutes.value)\r\n              .second(seconds.value)\r\n          )\r\n          break\r\n        case 'minutes':\r\n          ctx.emit(\r\n            'change',\r\n            props.spinnerDate\r\n              .hour(hours.value)\r\n              .minute(value)\r\n              .second(seconds.value)\r\n          )\r\n          break\r\n        case 'seconds':\r\n          ctx.emit(\r\n            'change',\r\n            props.spinnerDate\r\n              .hour(hours.value)\r\n              .minute(minutes.value)\r\n              .second(value)\r\n          )\r\n          break\r\n      }\r\n    }\r\n\r\n    const handleClick = (type, { value, disabled }) => {\r\n      if (!disabled) {\r\n        modifyDateField(type, value)\r\n        emitSelectRange(type)\r\n        adjustSpinner(type, value)\r\n      }\r\n    }\r\n\r\n    const handleScroll = (type) => {\r\n      isScrolling = true\r\n      debouncedResetScroll(type)\r\n      const value = Math.min(\r\n        Math.round(\r\n          (listRefsMap[type].$el.querySelector('.sg-scrollbar__wrap')\r\n            .scrollTop -\r\n            (scrollBarHeight(type) * 0.5 - 10) / typeItemHeight(type) +\r\n            3) /\r\n            typeItemHeight(type)\r\n        ),\r\n        type === 'hours' ? 23 : 59\r\n      )\r\n      modifyDateField(type, value)\r\n    }\r\n\r\n    const scrollBarHeight = (type) => {\r\n      return listRefsMap[type].$el.offsetHeight\r\n    }\r\n\r\n    const bindScrollEvent = () => {\r\n      const bindFuntion = (type) => {\r\n        if (listRefsMap[type] && listRefsMap[type].$el) {\r\n          listRefsMap[type].$el.querySelector('.sg-scrollbar__wrap').onscroll =\r\n            () => {\r\n              // TODO: scroll is emitted when set scrollTop programatically\r\n              // should find better solutions in the future!\r\n              handleScroll(type)\r\n            }\r\n        }\r\n      }\r\n      bindFuntion('hours')\r\n      bindFuntion('minutes')\r\n      bindFuntion('seconds')\r\n    }\r\n\r\n    onMounted(() => {\r\n      nextTick(() => {\r\n        bindScrollEvent()\r\n        adjustSpinners()\r\n        // set selection on the first hour part\r\n        if (props.role === 'start') emitSelectRange('hours')\r\n      })\r\n    })\r\n\r\n    const setRef = (scrollbar, type) => {\r\n      listRefsMap[type] = scrollbar\r\n    }\r\n\r\n    ctx.emit('set-option', [`${props.role}_scrollDown`, scrollDown])\r\n    ctx.emit('set-option', [`${props.role}_emitSelectRange`, emitSelectRange])\r\n\r\n    const { getHoursList, getMinutesList, getSecondsList } = getTimeLists(\r\n      props.disabledHours,\r\n      props.disabledMinutes,\r\n      props.disabledSeconds\r\n    )\r\n\r\n    watch(\r\n      () => props.spinnerDate,\r\n      () => {\r\n        if (isScrolling) return\r\n        adjustSpinners()\r\n      }\r\n    )\r\n\r\n    return {\r\n      setRef,\r\n      spinnerItems,\r\n      currentScrollbar,\r\n      hours,\r\n      minutes,\r\n      seconds,\r\n      hoursList,\r\n      minutesList,\r\n      getAmPmFlag,\r\n      emitSelectRange,\r\n      adjustCurrentSpinner,\r\n      typeItemHeight,\r\n      listHoursRef,\r\n      listMinutesRef,\r\n      listSecondsRef,\r\n      handleClick,\r\n      secondsList,\r\n      timePartsMap,\r\n      listMap,\r\n    }\r\n  },\r\n})\r\n</script>\r\n"],"names":["_resolveComponent","_normalizeClass","_createElementBlock","_Fragment","_renderList","_openBlock","_toDisplayString"],"mappings":";;;;;;kCACEA,gBA+BM,CAAA,cAAA,CAAA,CAAA;;WA9BaC,cAAY,CAAA,CAAA,iBAAA,EAAA,EAAA,aAAA,EAAA,IAAA,CAAA,WAAA,EAAA,CAAA,CAAA;AAAA,GAAA,EAAA;oCAGnB,IAAI,CAAA,EAAAC,kBAAA,CAAAC,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAAC,UAAA,CAAA,IAAA,CAAA,YAAA,EAAA,CAAA,IAAA,KAAA;;QACT,GAAG,EAAA,IAAA;AAAA,QACJ,OAAM,EAAA,IAAA;AAAA,QACN,mBAAW,IAAsB,CAAA,MAAA,CAAA,QAAA,EAAA,IAAA,CAAA;AAAA,QACjC,KAAA,EAAA,0BAAA;AAAA,QACA,YAAQ,EAAA,sBAAA;AAAA,QACR,YAAQ,EAAA,uBAAA;AAAA,QACP,QAAA,EAAA,EAAA;AAAA,QACA,GAAA,EAAA,IAAA;AAAA,QAAA,YAAA,EAAA,CAAA,MAAA,KAAA,IAAA,CAAA,eAAA,CAAA,IAAA,CAAA;AAG+C,QAAA,WAAA,EAAA,CAAA,MAAA,KAAA,IAAA,CAAA,oBAAA,CAAA,IAAA,CAAA;AAAA,OAAA,EAAA;;AACrC,WAAAC,SAAA,CAAA,IAAA,CAAA,EAAAH,kBAAA,CAAAC,QAAA,EAAA,IAAA,EAAAC,UAAA,CAAA,IAAA,CAAA,OAAA,CAAA,IAAA,CAAA,CAAA,KAAA,EAAA,CAAA,QAAA,EAAA,GAAA,KAAA;mBACJC,SAAC,EAAA,EAAAH,kBAAA,CAAA,IAAA,EAAA;AAAA,cAEL,GAAA;AAAA,cAAA,KAAA,EAAAD,cAAA,CAAA,CAAA,uBAAA,EAAA,EAAA,MAAA,EAAA,GAAA,KAAA,IAAA,CAAA,YAAA,CAAA,IAAA,CAAA,CAAA,KAAA,EAAA,QAAA,EAAA,CAAA,CAAA;AAEmB,cAAA,OAAA,EAAA,CAAA,MAAA,KAAA,IAAA,CAAA,WAAA,CAAA,IAAA,EAAA,EAAA,KAAA,EAAA,GAAA,EAAA,QAAA,EAAA,CAAA;AAAA,aAAA,EAAA;;gCAIpBK,eAEW,CAAA,CAAA,GAAA,IAAA,IAAA,CAAA,QAAA,GAAA,GAAA,GAAA,EAAA,IAAA,EAAA,GAAA,GAAA,CAAA,EAAA,KAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAAA,eAAA,CAAA,IAAA,CAAA,WAAA,CAAA,GAAA,CAAA,CAAA,EAAA,CAAA,CAAA;AAAA,eAAA,EAAA,EAAA,CAAA,KAAAD,SAAA,EAAA,EAAAH,kBAAA,CAAAC,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;;;;;;;;;;;;;;;"}