{"version":3,"file":"basic-time-spinner.mjs","sources":["../../../../../../../packages/components/time-picker/src/time-picker-com/basic-time-spinner.vue"],"sourcesContent":["<template>\n  <div class=\"time-spinner\" :class=\"{ 'has-seconds': showSeconds }\">\n    <template v-if=\"!arrowControl\">\n      <hl-scrollbar\n        v-for=\"item in spinnerItems\"\n        :key=\"item\"\n        :ref=\"(scollbar) => setRef(scollbar, item)\"\n        class=\"spinner-wrapper\"\n        wrap-style=\"max-height: inherit;\"\n        view-class=\"spinner-list\"\n        noresize\n        tag=\"ul\"\n        @mouseenter=\"emitSelectRange(item)\"\n        @mousemove=\"adjustCurrentSpinner(item)\"\n      >\n        <li\n          v-for=\"(disabled, key) in timeList[item]\"\n          :key=\"key\"\n          class=\"spinner-item\"\n          :class=\"{ 'active': key === timePartials[item], disabled }\"\n          @click=\"handleClick(item, { value: key, disabled })\"\n        >\n          <template v-if=\"item === 'hours'\">\n            {{ ('0' + (amPmMode ? (key % 12 || 12) : key )).slice(-2) }}{{ getAmPmFlag(key) }}\n          </template>\n          <template v-else>\n            {{ ('0' + key).slice(-2) }}\n          </template>\n        </li>\n      </hl-scrollbar>\n    </template>\n    <template v-if=\"arrowControl\">\n      <div\n        v-for=\"item in spinnerItems\"\n        :key=\"item\"\n        class=\"spinner-wrapper is-arrow\"\n        @mouseenter=\"emitSelectRange(item)\"\n      >\n        <hl-button\n          v-repeat-click=\"onDecrement\"\n          no-fill\n          size=\"sm\"\n          class=\"spinner-arrow up bg-transparent hover:text-hover\"\n        >\n          <template #icon>\n            <hl-icon>\n              <system-arrow-up />\n            </hl-icon>\n          </template>\n        </hl-button>\n        <hl-button\n          v-repeat-click=\"onIncrement\"\n          no-fill\n          size=\"sm\"\n          class=\"spinner-arrow down bg-transparent hover:text-hover\"\n        >\n          <template #icon>\n            <hl-icon>\n              <system-arrow-down />\n            </hl-icon>\n          </template>\n        </hl-button>\n\n        <ul class=\"spinner-list group-item\">\n          <li\n            v-for=\"(time, key) in arrowControlTimeList[item]\"\n            :key=\"key\"\n            class=\"spinner-item\"\n            :class=\"{ 'active': time === timePartials[item], 'disabled': timeList[item][time] }\"\n          >\n            <template v-if=\"typeof time === 'number'\">\n              <template v-if=\"item === 'hours'\">\n                {{ ('0' + (amPmMode ? time % 12 || 12 : time)).slice(-2)\n                }}{{ getAmPmFlag(time) }}\n              </template>\n              <template v-else>\n                {{ ('0' + time).slice(-2) }}\n              </template>\n            </template>\n          </li>\n        </ul>\n      </div>\n    </template>\n  </div>\n</template>\n<script lang=\"ts\" setup>\nimport { computed, nextTick, onMounted, ref, unref, watch } from 'vue'\nimport { debounce } from 'lodash-unified'\nimport { vRepeatClick } from '@hongluan-ui/directives'\nimport HlScrollbar from '@hongluan-ui/components/scrollbar'\nimport HlButton from '@hongluan-ui/components/button'\nimport HlIcon from '@hongluan-ui/components/icon'\nimport { getStyle } from '@hongluan-ui/utils'\nimport { SystemArrowUp, SystemArrowDown } from '@hongluan-ui/components/system-icon'\nimport { timeUnits } from '../constants'\nimport { buildTimeList } from '../utils'\nimport { basicTimeSpinnerProps } from '../props/basic-time-spinner'\nimport { getTimeLists } from '../composables/use-time-picker'\n\nimport type { Ref } from 'vue'\nimport type { ScrollbarInstance } from '@hongluan-ui/components/scrollbar'\nimport type { TimeUnit } from '../constants'\nimport type { TimeList } from '../utils'\n\nconst props = defineProps(basicTimeSpinnerProps)\nconst emit = defineEmits(['change', 'select-range', 'set-option'])\n\nconst { getHoursList, getMinutesList, getSecondsList } = getTimeLists(\n  props.disabledHours,\n  props.disabledMinutes,\n  props.disabledSeconds,\n)\n\n// data\nlet isScrolling = false\n\nconst currentScrollbar = ref<TimeUnit>()\nconst listHoursRef = ref<ScrollbarInstance>()\nconst listMinutesRef = ref<ScrollbarInstance>()\nconst listSecondsRef = ref<ScrollbarInstance>()\nconst listRefsMap: Record<TimeUnit, Ref<ScrollbarInstance | undefined>> = {\n  hours: listHoursRef,\n  minutes: listMinutesRef,\n  seconds: listSecondsRef,\n}\n\n// computed\nconst spinnerItems = computed(() => {\n  return props.showSeconds ? timeUnits : timeUnits.slice(0, 2)\n})\n\nconst timePartials = computed<Record<TimeUnit, number>>(() => {\n  const { spinnerDate } = props\n  const hours = spinnerDate.hour()\n  const minutes = spinnerDate.minute()\n  const seconds = spinnerDate.second()\n  return { hours, minutes, seconds }\n})\n\nconst timeList = computed(() => {\n  const { hours, minutes } = unref(timePartials)\n  return {\n    hours: getHoursList(props.role),\n    minutes: getMinutesList(hours, props.role),\n    seconds: getSecondsList(hours, minutes, props.role),\n  }\n})\n\nconst arrowControlTimeList = computed<Record<TimeUnit, TimeList>>(() => {\n  const { hours, minutes, seconds } = unref(timePartials)\n\n  return {\n    hours: buildTimeList(hours, 23),\n    minutes: buildTimeList(minutes, 59),\n    seconds: buildTimeList(seconds, 59),\n  }\n})\n\nconst debouncedResetScroll = debounce(type => {\n  isScrolling = false\n  adjustCurrentSpinner(type)\n}, 200)\n\nconst getAmPmFlag = (hour: number) => {\n  const shouldShowAmPm = !!props.amPmMode\n  if (!shouldShowAmPm) return ''\n  const isCapital = props.amPmMode === 'A'\n  // todo locale\n  let content = hour < 12 ? ' am' : ' pm'\n  if (isCapital) content = content.toUpperCase()\n  return content\n}\n\nconst emitSelectRange = (type: TimeUnit) => {\n  let range\n\n  switch (type) {\n    case 'hours':\n      range = [0, 2]\n      break\n    case 'minutes':\n      range = [3, 5]\n      break\n    case 'seconds':\n      range = [6, 8]\n      break\n  }\n  const [left, right] = range\n\n  emit('select-range', left, right)\n  currentScrollbar.value = type\n}\n\nconst adjustCurrentSpinner = (type: TimeUnit) => {\n  adjustSpinner(type, unref(timePartials)[type])\n}\n\nconst adjustSpinners = () => {\n  adjustCurrentSpinner('hours')\n  adjustCurrentSpinner('minutes')\n  adjustCurrentSpinner('seconds')\n}\n\nconst getScrollbarElement = (el: HTMLElement) =>\n  el.querySelector(`.scrollbar-wrap`) as HTMLElement\n\nconst adjustSpinner = (type: TimeUnit, value: number) => {\n  if (props.arrowControl) return\n  const scrollbar = unref(listRefsMap[type])\n  if (scrollbar && scrollbar.$el) {\n    getScrollbarElement(scrollbar.$el).scrollTop = Math.max(\n      0,\n      value * typeItemHeight(type),\n    )\n  }\n}\n\nconst typeItemHeight = (type: TimeUnit): number => {\n  const scrollbar = unref(listRefsMap[type])\n  const listItem = scrollbar?.$el.querySelector('li')\n  if (listItem) {\n    return Number.parseFloat(getStyle(listItem, 'height')) || 0\n  }\n  return 0\n}\n\nconst onIncrement = () => {\n  scrollDown(1)\n}\n\nconst onDecrement = () => {\n  scrollDown(-1)\n}\n\nconst scrollDown = (step: number) => {\n  if (!currentScrollbar.value) {\n    emitSelectRange('hours')\n  }\n\n  const label = currentScrollbar.value!\n  const now = unref(timePartials)[label]\n  const total = currentScrollbar.value === 'hours' ? 24 : 60\n  const next = findNextUnDisabled(label, now, step, total)\n\n  modifyDateField(label, next)\n  adjustSpinner(label, next)\n  nextTick(() => emitSelectRange(label))\n}\n\nconst findNextUnDisabled = (\n  type: TimeUnit,\n  now: number,\n  step: number,\n  total: number,\n) => {\n  let next = (now + step + total) % total\n  const list = unref(timeList)[type]\n  while (list[next] && next !== now) {\n    next = (next + step + total) % total\n  }\n  return next\n}\n\nconst modifyDateField = (type: TimeUnit, value: number) => {\n  const list = unref(timeList)[type]\n  const isDisabled = list[value]\n  if (isDisabled) return\n\n  const { hours, minutes, seconds } = unref(timePartials)\n\n  let changeTo\n  switch (type) {\n    case 'hours':\n      changeTo = props.spinnerDate.hour(value).minute(minutes).second(seconds)\n      break\n    case 'minutes':\n      changeTo = props.spinnerDate.hour(hours).minute(value).second(seconds)\n      break\n    case 'seconds':\n      changeTo = props.spinnerDate.hour(hours).minute(minutes).second(value)\n      break\n  }\n  emit('change', changeTo)\n}\n\nconst handleClick = (\n  type: TimeUnit,\n  { value, disabled }: { value: number; disabled: boolean; },\n) => {\n  if (!disabled) {\n    modifyDateField(type, value)\n    emitSelectRange(type)\n    adjustSpinner(type, value)\n  }\n}\n\nconst handleScroll = (type: TimeUnit) => {\n  isScrolling = true\n  debouncedResetScroll(type)\n  const value = Math.min(\n    Math.round(\n      (getScrollbarElement(unref(listRefsMap[type])!.$el).scrollTop -\n        (scrollBarHeight(type) * 0.5 - 10) / typeItemHeight(type) +\n        3) /\n        typeItemHeight(type),\n    ),\n    type === 'hours' ? 23 : 59,\n  )\n  modifyDateField(type, value)\n}\n\nconst scrollBarHeight = (type: TimeUnit) => {\n  return unref(listRefsMap[type])!.$el.offsetHeight\n}\n\nconst bindScrollEvent = () => {\n  const bindFunction = (type: TimeUnit) => {\n    const scrollbar = unref(listRefsMap[type])\n    if (scrollbar && scrollbar.$el) {\n      getScrollbarElement(scrollbar.$el).onscroll = () => {\n        // TODO: scroll is emitted when set scrollTop programmatically\n        // should find better solutions in the future!\n        handleScroll(type)\n      }\n    }\n  }\n  bindFunction('hours')\n  bindFunction('minutes')\n  bindFunction('seconds')\n}\n\nonMounted(() => {\n  nextTick(() => {\n    !props.arrowControl && bindScrollEvent()\n    adjustSpinners()\n    // set selection on the first hour part\n    if (props.role === 'start') emitSelectRange('hours')\n  })\n})\n\nconst setRef = (scrollbar: ScrollbarInstance, type: TimeUnit) => {\n  listRefsMap[type].value = scrollbar\n}\n\nemit('set-option', [`${props.role}_scrollDown`, scrollDown])\nemit('set-option', [`${props.role}_emitSelectRange`, emitSelectRange])\n\nwatch(\n  () => props.spinnerDate,\n  () => {\n    if (isScrolling) return\n    adjustSpinners()\n  },\n)\n</script>\n"],"names":[],"mappings":"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"}