UNPKG

@opensig/opendesign

Version:

207 lines (206 loc) 8.18 kB
import { defineComponent, mergeModels, useModel, computed, ref, onMounted, watch, onUnmounted, createBlock, openBlock, unref, withCtx, createElementVNode, createElementBlock, createCommentVNode, Fragment, renderList, normalizeClass, toDisplayString, nextTick } from "vue"; import { useCssVar } from "@vueuse/core"; import { OScroller } from "../../scrollbar/index.mjs"; import "../../_utils/is.mjs"; import "../../hooks/use-theme.mjs"; import { useScreen } from "../../hooks/use-screen.mjs"; 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__ */ defineComponent({ __name: "TimeColumn", props: /* @__PURE__ */ mergeModels({ options: {}, disabledOptions: {}, noResponsive: { type: Boolean } }, { "modelValue": { required: true }, "modelModifiers": {} }), emits: /* @__PURE__ */ 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 = useModel(__props, "modelValue"); const { isPhonePad } = useScreen(); const isResponding = computed(() => !props.noResponsive && isPhonePad.value); const columnRef = ref(); const listRef = ref(); const itemsRef = ref(); const itemInnerHeightVar = useCssVar("--time-panel-item-height", listRef, { initialValue: "48px" }); const itemInnerHeight = computed(() => Number.parseInt(itemInnerHeightVar.value)); const itemGapVar = useCssVar("--time-panel-item-gap", listRef, { initialValue: "4px" }); const itemGap = computed(() => Number.parseInt(itemGapVar.value)); const itemHeight = computed(() => itemInnerHeight.value + itemGap.value / 2); const showItemCountVar = useCssVar("--time-panel-col-show-item-count", listRef, { initialValue: "5" }); const showItemCount = computed(() => Number.parseInt(showItemCountVar.value)); const activeItemPadding = computed(() => itemHeight.value * (showItemCount.value - 1) / 2); let changedByOut = false; const scrollToItem = async (smooth = false) => { var _a; await 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); }; onMounted(() => { scrollToItem(false); }); watch(isResponding, () => { scrollToItem(false); }); onUnmounted(() => { if (scrollEndTimer) clearTimeout(scrollEndTimer); }); __expose({ scrollToItem }); return (_ctx, _cache) => { return openBlock(), createBlock(unref(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: withCtx(() => [ _cache[1] || (_cache[1] = createElementVNode( "div", { class: "o-time-panel-indicator" }, null, -1 /* CACHED */ )), createElementVNode( "div", { ref_key: "listRef", ref: listRef, class: "o-time-panel-column-list" }, [ isResponding.value ? (openBlock(), createElementBlock("div", _hoisted_1)) : createCommentVNode("v-if", true), (openBlock(true), createElementBlock( Fragment, null, renderList(props.options, (item) => { return openBlock(), createElementBlock("div", { key: item.value, ref_for: true, ref_key: "itemsRef", ref: itemsRef, class: normalizeClass(["o-time-panel-item", { active: modelValue.value === item.value, disabled: isItemDisabled(item.value) }]), "data-item-value": item.value, onClick: ($event) => handleItemClick(item) }, [ createElementVNode( "div", _hoisted_3, toDisplayString(item.label), 1 /* TEXT */ ) ], 10, _hoisted_2); }), 128 /* KEYED_FRAGMENT */ )), _cache[0] || (_cache[0] = createElementVNode( "div", { class: "o-time-panel-column-spacer" }, null, -1 /* CACHED */ )) ], 512 /* NEED_PATCH */ ) ]), _: 1 /* STABLE */ }, 8, ["show-type"]); }; } }); export { _sfc_main as default };