hongluan-ui
Version:
Hongluan Component Library for Vue 3
1 lines • 14.5 kB
Source Map (JSON)
{"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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"}