@opensig/opendesign
Version:
206 lines (205 loc) • 8.11 kB
JavaScript
;
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;