UNPKG

@opensig/opendesign

Version:

206 lines (205 loc) 8.11 kB
"use strict"; const vue = require("vue"); const core = require("@vueuse/core"); const index = require("../../scrollbar/index.js"); require("../../_utils/is.js"); require("../../hooks/use-theme.js"); const useScreen = require("../../hooks/use-screen.js"); const _hoisted_1 = { key: 0, class: "o-time-panel-column-spacer" }; const _hoisted_2 = ["data-item-value", "onClick"]; const _hoisted_3 = { class: "o-time-panel-item__inner" }; const LANDED_THRESHOLD = 5; const WHEEL_STEP = 3; const _sfc_main = /* @__PURE__ */ vue.defineComponent({ __name: "TimeColumn", props: /* @__PURE__ */ vue.mergeModels({ options: {}, disabledOptions: {}, noResponsive: { type: Boolean } }, { "modelValue": { required: true }, "modelModifiers": {} }), emits: /* @__PURE__ */ vue.mergeModels(["change"], ["update:modelValue"]), setup(__props, { expose: __expose, emit: __emit }) { function findLandedItemValue({ el, containerTop, responding, itemPadding }) { const { top } = el.getBoundingClientRect(); const inRespondingMiddle = responding && Math.abs(itemPadding - (top - containerTop)) < LANDED_THRESHOLD; const inUnrespondingTop = !responding && top - containerTop < LANDED_THRESHOLD; if (inRespondingMiddle || inUnrespondingTop) { return Number.parseInt(el.dataset.itemValue); } return null; } const props = __props; const emits = __emit; const modelValue = vue.useModel(__props, "modelValue"); const { isPhonePad } = useScreen.useScreen(); const isResponding = vue.computed(() => !props.noResponsive && isPhonePad.value); const columnRef = vue.ref(); const listRef = vue.ref(); const itemsRef = vue.ref(); const itemInnerHeightVar = core.useCssVar("--time-panel-item-height", listRef, { initialValue: "48px" }); const itemInnerHeight = vue.computed(() => Number.parseInt(itemInnerHeightVar.value)); const itemGapVar = core.useCssVar("--time-panel-item-gap", listRef, { initialValue: "4px" }); const itemGap = vue.computed(() => Number.parseInt(itemGapVar.value)); const itemHeight = vue.computed(() => itemInnerHeight.value + itemGap.value / 2); const showItemCountVar = core.useCssVar("--time-panel-col-show-item-count", listRef, { initialValue: "5" }); const showItemCount = vue.computed(() => Number.parseInt(showItemCountVar.value)); const activeItemPadding = vue.computed(() => itemHeight.value * (showItemCount.value - 1) / 2); let changedByOut = false; const scrollToItem = async (smooth = false) => { var _a; await vue.nextTick(); if (!columnRef.value) return; const activeItem = (_a = columnRef.value.getContainerEl()) == null ? void 0 : _a.querySelector(".active"); if (!activeItem) return; changedByOut = !smooth; if (isResponding.value) { columnRef.value.scrollTo({ top: activeItem.offsetTop - activeItemPadding.value, behavior: smooth ? "smooth" : "instant" }); } else { columnRef.value.scrollTo({ top: activeItem.offsetTop, behavior: smooth ? "smooth" : "instant" }); } }; const handleWheel = (e) => { var _a; e.preventDefault(); const direction = e.deltaY > 0 ? itemHeight.value : -itemHeight.value; (_a = columnRef.value) == null ? void 0 : _a.scrollBy({ top: direction * WHEEL_STEP, behavior: "smooth" }); }; const isItemDisabled = (item) => { var _a; return ((_a = props.disabledOptions) == null ? void 0 : _a.includes(item)) ?? false; }; const findNearestEnabled = (value) => { const enabled = props.options.filter((o) => !isItemDisabled(o.value)); if (enabled.length === 0) return null; return enabled.reduce((closest, cur) => Math.abs(cur.value - value) < Math.abs(closest - value) ? cur.value : closest, enabled[0].value); }; let scrollEndTimer = null; let isAutoScrolling = false; const onScrollEnd = (landedValue) => { if (landedValue !== null && isItemDisabled(landedValue)) { const nearest = findNearestEnabled(landedValue); if (nearest !== null) { modelValue.value = nearest; isAutoScrolling = true; scrollToItem(true); emits("change", nearest); } } }; const handleScroll = () => { var _a, _b, _c; if (isAutoScrolling) { isAutoScrolling = false; return; } const containerTop = ((_b = (_a = columnRef.value) == null ? void 0 : _a.getContainerEl()) == null ? void 0 : _b.getBoundingClientRect().top) ?? 0; let landedValue = null; (_c = itemsRef.value) == null ? void 0 : _c.forEach((el) => { const v = findLandedItemValue({ el, containerTop, responding: isResponding.value, itemPadding: activeItemPadding.value }); if (v !== null) landedValue = v; }); if (landedValue !== null && !isItemDisabled(landedValue)) { modelValue.value = landedValue; } const _changedByOut = changedByOut; changedByOut = false; if (!_changedByOut) emits("change", modelValue.value); clearTimeout(scrollEndTimer); scrollEndTimer = setTimeout(() => onScrollEnd(landedValue), 150); }; const handleItemClick = (item) => { if (isItemDisabled(item.value)) return; modelValue.value = item.value; scrollToItem(true); }; vue.onMounted(() => { scrollToItem(false); }); vue.watch(isResponding, () => { scrollToItem(false); }); vue.onUnmounted(() => { if (scrollEndTimer) clearTimeout(scrollEndTimer); }); __expose({ scrollToItem }); return (_ctx, _cache) => { return vue.openBlock(), vue.createBlock(vue.unref(index.OScroller), { ref_key: "columnRef", ref: columnRef, size: "small", "show-type": isResponding.value ? "never" : "auto", "disabled-x": "", class: "o-time-panel-column-scroller", "wrap-class": "o-time-panel-column", onScroll: handleScroll, onWheel: handleWheel }, { default: vue.withCtx(() => [ _cache[1] || (_cache[1] = vue.createElementVNode( "div", { class: "o-time-panel-indicator" }, null, -1 /* CACHED */ )), vue.createElementVNode( "div", { ref_key: "listRef", ref: listRef, class: "o-time-panel-column-list" }, [ isResponding.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1)) : vue.createCommentVNode("v-if", true), (vue.openBlock(true), vue.createElementBlock( vue.Fragment, null, vue.renderList(props.options, (item) => { return vue.openBlock(), vue.createElementBlock("div", { key: item.value, ref_for: true, ref_key: "itemsRef", ref: itemsRef, class: vue.normalizeClass(["o-time-panel-item", { active: modelValue.value === item.value, disabled: isItemDisabled(item.value) }]), "data-item-value": item.value, onClick: ($event) => handleItemClick(item) }, [ vue.createElementVNode( "div", _hoisted_3, vue.toDisplayString(item.label), 1 /* TEXT */ ) ], 10, _hoisted_2); }), 128 /* KEYED_FRAGMENT */ )), _cache[0] || (_cache[0] = vue.createElementVNode( "div", { class: "o-time-panel-column-spacer" }, null, -1 /* CACHED */ )) ], 512 /* NEED_PATCH */ ) ]), _: 1 /* STABLE */ }, 8, ["show-type"]); }; } }); module.exports = _sfc_main;