element-plus
Version:
A Component Library for Vue 3
316 lines (313 loc) • 13 kB
JavaScript
import { defineComponent, inject, ref, computed, unref, onMounted, nextTick, watch, openBlock, createElementBlock, normalizeClass, Fragment, renderList, createBlock, withCtx, createTextVNode, toDisplayString, createCommentVNode, withDirectives, createVNode, createElementVNode } from 'vue';
import { debounce } from 'lodash-unified';
import { ElScrollbar } from '../../../scrollbar/index.mjs';
import { ElIcon } from '../../../icon/index.mjs';
import { ArrowUp, ArrowDown } from '@element-plus/icons-vue';
import { timeUnits, DEFAULT_FORMATS_TIME } from '../constants.mjs';
import { buildTimeList } from '../utils.mjs';
import { basicTimeSpinnerProps } from '../props/basic-time-spinner.mjs';
import { getTimeLists } from '../composables/use-time-picker.mjs';
import _export_sfc from '../../../../_virtual/plugin-vue_export-helper.mjs';
import { vRepeatClick } from '../../../../directives/repeat-click/index.mjs';
import { CHANGE_EVENT } from '../../../../constants/event.mjs';
import { useNamespace } from '../../../../hooks/use-namespace/index.mjs';
import { getStyle } from '../../../../utils/dom/style.mjs';
import { isNumber } from '../../../../utils/types.mjs';
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "basic-time-spinner",
props: basicTimeSpinnerProps,
emits: [CHANGE_EVENT, "select-range", "set-option"],
setup(__props, { emit }) {
const props = __props;
const pickerBase = inject("EP_PICKER_BASE");
const { isRange, format } = pickerBase.props;
const ns = useNamespace("time");
const { getHoursList, getMinutesList, getSecondsList } = getTimeLists(props.disabledHours, props.disabledMinutes, props.disabledSeconds);
let isScrolling = false;
const currentScrollbar = ref();
const listHoursRef = ref();
const listMinutesRef = ref();
const listSecondsRef = ref();
const listRefsMap = {
hours: listHoursRef,
minutes: listMinutesRef,
seconds: listSecondsRef
};
const spinnerItems = computed(() => {
return props.showSeconds ? timeUnits : timeUnits.slice(0, 2);
});
const timePartials = computed(() => {
const { spinnerDate } = props;
const hours = spinnerDate.hour();
const minutes = spinnerDate.minute();
const seconds = spinnerDate.second();
return { hours, minutes, seconds };
});
const timeList = computed(() => {
const { hours, minutes } = unref(timePartials);
const { role, spinnerDate } = props;
const compare = !isRange ? spinnerDate : void 0;
return {
hours: getHoursList(role, compare),
minutes: getMinutesList(hours, role, compare),
seconds: getSecondsList(hours, minutes, role, compare)
};
});
const arrowControlTimeList = computed(() => {
const { hours, minutes, seconds } = unref(timePartials);
return {
hours: buildTimeList(hours, 23),
minutes: buildTimeList(minutes, 59),
seconds: buildTimeList(seconds, 59)
};
});
const debouncedResetScroll = debounce((type) => {
isScrolling = false;
adjustCurrentSpinner(type);
}, 200);
const getAmPmFlag = (hour) => {
const shouldShowAmPm = !!props.amPmMode;
if (!shouldShowAmPm)
return "";
const isCapital = props.amPmMode === "A";
let content = hour < 12 ? " am" : " pm";
if (isCapital)
content = content.toUpperCase();
return content;
};
const emitSelectRange = (type) => {
let range = [0, 0];
if (!format || format === DEFAULT_FORMATS_TIME) {
switch (type) {
case "hours":
range = [0, 2];
break;
case "minutes":
range = [3, 5];
break;
case "seconds":
range = [6, 8];
break;
}
}
const [left, right] = range;
emit("select-range", left, right);
currentScrollbar.value = type;
};
const adjustCurrentSpinner = (type) => {
adjustSpinner(type, unref(timePartials)[type]);
};
const adjustSpinners = () => {
adjustCurrentSpinner("hours");
adjustCurrentSpinner("minutes");
adjustCurrentSpinner("seconds");
};
const getScrollbarElement = (el) => el.querySelector(`.${ns.namespace.value}-scrollbar__wrap`);
const adjustSpinner = (type, value) => {
if (props.arrowControl)
return;
const scrollbar = unref(listRefsMap[type]);
if (scrollbar && scrollbar.$el) {
getScrollbarElement(scrollbar.$el).scrollTop = Math.max(0, value * typeItemHeight(type));
}
};
const typeItemHeight = (type) => {
const scrollbar = unref(listRefsMap[type]);
const listItem = scrollbar == null ? void 0 : scrollbar.$el.querySelector("li");
if (listItem) {
return Number.parseFloat(getStyle(listItem, "height")) || 0;
}
return 0;
};
const onIncrement = () => {
scrollDown(1);
};
const onDecrement = () => {
scrollDown(-1);
};
const scrollDown = (step) => {
if (!currentScrollbar.value) {
emitSelectRange("hours");
}
const label = currentScrollbar.value;
const now = unref(timePartials)[label];
const total = currentScrollbar.value === "hours" ? 24 : 60;
const next = findNextUnDisabled(label, now, step, total);
modifyDateField(label, next);
adjustSpinner(label, next);
nextTick(() => emitSelectRange(label));
};
const findNextUnDisabled = (type, now, step, total) => {
let next = (now + step + total) % total;
const list = unref(timeList)[type];
while (list[next] && next !== now) {
next = (next + step + total) % total;
}
return next;
};
const modifyDateField = (type, value) => {
const list = unref(timeList)[type];
const isDisabled = list[value];
if (isDisabled)
return;
const { hours, minutes, seconds } = unref(timePartials);
let changeTo;
switch (type) {
case "hours":
changeTo = props.spinnerDate.hour(value).minute(minutes).second(seconds);
break;
case "minutes":
changeTo = props.spinnerDate.hour(hours).minute(value).second(seconds);
break;
case "seconds":
changeTo = props.spinnerDate.hour(hours).minute(minutes).second(value);
break;
}
emit(CHANGE_EVENT, changeTo);
};
const handleClick = (type, { value, disabled }) => {
if (!disabled) {
modifyDateField(type, value);
emitSelectRange(type);
adjustSpinner(type, value);
}
};
const handleScroll = (type) => {
const scrollbar = unref(listRefsMap[type]);
if (!scrollbar)
return;
isScrolling = true;
debouncedResetScroll(type);
const value = Math.min(Math.round((getScrollbarElement(scrollbar.$el).scrollTop - (scrollBarHeight(type) * 0.5 - 10) / typeItemHeight(type) + 3) / typeItemHeight(type)), type === "hours" ? 23 : 59);
modifyDateField(type, value);
};
const scrollBarHeight = (type) => {
return unref(listRefsMap[type]).$el.offsetHeight;
};
const bindScrollEvent = () => {
const bindFunction = (type) => {
const scrollbar = unref(listRefsMap[type]);
if (scrollbar && scrollbar.$el) {
getScrollbarElement(scrollbar.$el).onscroll = () => {
handleScroll(type);
};
}
};
bindFunction("hours");
bindFunction("minutes");
bindFunction("seconds");
};
onMounted(() => {
nextTick(() => {
!props.arrowControl && bindScrollEvent();
adjustSpinners();
if (props.role === "start")
emitSelectRange("hours");
});
});
const setRef = (scrollbar, type) => {
listRefsMap[type].value = scrollbar != null ? scrollbar : void 0;
};
emit("set-option", [`${props.role}_scrollDown`, scrollDown]);
emit("set-option", [`${props.role}_emitSelectRange`, emitSelectRange]);
watch(() => props.spinnerDate, () => {
if (isScrolling)
return;
adjustSpinners();
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
class: normalizeClass([unref(ns).b("spinner"), { "has-seconds": _ctx.showSeconds }])
}, [
!_ctx.arrowControl ? (openBlock(true), createElementBlock(Fragment, { key: 0 }, renderList(unref(spinnerItems), (item) => {
return openBlock(), createBlock(unref(ElScrollbar), {
key: item,
ref_for: true,
ref: (scrollbar) => setRef(scrollbar, item),
class: normalizeClass(unref(ns).be("spinner", "wrapper")),
"wrap-style": "max-height: inherit;",
"view-class": unref(ns).be("spinner", "list"),
noresize: "",
tag: "ul",
onMouseenter: ($event) => emitSelectRange(item),
onMousemove: ($event) => adjustCurrentSpinner(item)
}, {
default: withCtx(() => [
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(timeList)[item], (disabled, key) => {
return openBlock(), createElementBlock("li", {
key,
class: normalizeClass([
unref(ns).be("spinner", "item"),
unref(ns).is("active", key === unref(timePartials)[item]),
unref(ns).is("disabled", disabled)
]),
onClick: ($event) => handleClick(item, { value: key, disabled })
}, [
item === "hours" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
createTextVNode(toDisplayString(("0" + (_ctx.amPmMode ? key % 12 || 12 : key)).slice(-2)) + toDisplayString(getAmPmFlag(key)), 1)
], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
createTextVNode(toDisplayString(("0" + key).slice(-2)), 1)
], 64))
], 10, ["onClick"]);
}), 128))
]),
_: 2
}, 1032, ["class", "view-class", "onMouseenter", "onMousemove"]);
}), 128)) : createCommentVNode("v-if", true),
_ctx.arrowControl ? (openBlock(true), createElementBlock(Fragment, { key: 1 }, renderList(unref(spinnerItems), (item) => {
return openBlock(), createElementBlock("div", {
key: item,
class: normalizeClass([unref(ns).be("spinner", "wrapper"), unref(ns).is("arrow")]),
onMouseenter: ($event) => emitSelectRange(item)
}, [
withDirectives((openBlock(), createBlock(unref(ElIcon), {
class: normalizeClass(["arrow-up", unref(ns).be("spinner", "arrow")])
}, {
default: withCtx(() => [
createVNode(unref(ArrowUp))
]),
_: 1
}, 8, ["class"])), [
[unref(vRepeatClick), onDecrement]
]),
withDirectives((openBlock(), createBlock(unref(ElIcon), {
class: normalizeClass(["arrow-down", unref(ns).be("spinner", "arrow")])
}, {
default: withCtx(() => [
createVNode(unref(ArrowDown))
]),
_: 1
}, 8, ["class"])), [
[unref(vRepeatClick), onIncrement]
]),
createElementVNode("ul", {
class: normalizeClass(unref(ns).be("spinner", "list"))
}, [
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(arrowControlTimeList)[item], (time, key) => {
return openBlock(), createElementBlock("li", {
key,
class: normalizeClass([
unref(ns).be("spinner", "item"),
unref(ns).is("active", time === unref(timePartials)[item]),
unref(ns).is("disabled", unref(timeList)[item][time])
])
}, [
unref(isNumber)(time) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
item === "hours" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
createTextVNode(toDisplayString(("0" + (_ctx.amPmMode ? time % 12 || 12 : time)).slice(-2)) + toDisplayString(getAmPmFlag(time)), 1)
], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
createTextVNode(toDisplayString(("0" + time).slice(-2)), 1)
], 64))
], 64)) : createCommentVNode("v-if", true)
], 2);
}), 128))
], 2)
], 42, ["onMouseenter"]);
}), 128)) : createCommentVNode("v-if", true)
], 2);
};
}
});
var TimeSpinner = /* @__PURE__ */ _export_sfc(_sfc_main, [["__file", "basic-time-spinner.vue"]]);
export { TimeSpinner as default };
//# sourceMappingURL=basic-time-spinner.mjs.map