UNPKG

@opensig/opendesign

Version:

300 lines (299 loc) 9.89 kB
import { defineComponent, reactive, inject, ref, toRefs, computed, watch, onMounted, onUnmounted, createElementBlock, openBlock, Fragment, createElementVNode, createBlock, createCommentVNode, normalizeStyle, normalizeClass, unref, withCtx, createTextVNode, toDisplayString } from "vue"; import { OPopover } from "../popover/index.mjs"; import { pageUp, pageDown, End, Home, ArrowUp, ArrowRight, ArrowDown, ArrowLeft } from "../_utils/keycode.mjs"; import { mergeClass } from "../_utils/vue-utils.mjs"; import { sliderInjectKey } from "./provide.mjs"; import { sliderButtonProps } from "./types.mjs"; const _hoisted_1 = ["tabindex"]; const _hoisted_2 = { key: 0, class: "o-slider-circle" }; const _sfc_main = /* @__PURE__ */ defineComponent({ __name: "OSliderButton", props: sliderButtonProps, emits: ["update:modelValue"], setup(__props, { expose: __expose, emit: __emit }) { const props = __props; const emit = __emit; const initData = reactive({ hovering: false, dragging: false, isClick: false, startX: 0, currentX: 0, startY: 0, currentY: 0, startPosition: 0, newPosition: 0, oldValue: props.modelValue }); const { disabled, min, max, step, sliderSize, emitChange, resetSize, updateDragging } = inject(sliderInjectKey); const button = ref(); const { hovering, dragging } = toRefs(initData); const formatValue = computed(() => { return props.modelValue; }); const showToolTip = computed(() => { return initData.hovering || initData.dragging; }); const currentPosition = computed(() => { return `${(props.modelValue - min.value) / (max.value - min.value) * 100}%`; }); const wrapperStyle = computed(() => { return { left: currentPosition.value }; }); const handleMouseEnter = () => { initData.hovering = true; }; const handleMouseLeave = () => { initData.hovering = false; }; const onButtonDown = (event) => { if (disabled.value) { return; } event.preventDefault(); handleDragStart(event); window.addEventListener("mousemove", handleDragging); window.addEventListener("touchmove", handleDragging); window.addEventListener("mouseup", handleDragEnd); window.addEventListener("touchend", handleDragEnd); window.addEventListener("contextmenu", handleDragEnd); button.value.focus(); }; const incrementPosition = (amount) => { if (disabled.value) { return; } initData.newPosition = Number.parseFloat(currentPosition.value) + amount / (max.value - min.value) * 100; setPosition(initData.newPosition); emitChange(); }; const onLeftKeyDown = () => { incrementPosition(-step.value); }; const onRightKeyDown = () => { incrementPosition(step.value); }; const onPageDownKeyDown = () => { incrementPosition(-step.value * 4); }; const onPageUpKeyDown = () => { incrementPosition(step.value * 4); }; const onHomeKeyDown = () => { if (disabled.value) { return; } setPosition(0); emitChange(); }; const onEndKeyDown = () => { if (disabled.value) { return; } setPosition(100); emitChange(); }; const onKeyDown = (event) => { const code = event.code; let isPreventDefault = true; switch (code) { case ArrowLeft.key: case ArrowDown.key: onLeftKeyDown(); break; case ArrowRight.key: case ArrowUp.key: onRightKeyDown(); break; case Home.key: onHomeKeyDown(); break; case End.key: onEndKeyDown(); break; case pageDown.key: onPageDownKeyDown(); break; case pageUp.key: onPageUpKeyDown(); break; default: isPreventDefault = false; break; } isPreventDefault && event.preventDefault(); }; const getClientXY = (event) => { let clientX; let clientY; if (event.type.startsWith("touch")) { clientY = event.touches[0].clientY; clientX = event.touches[0].clientX; } else { clientY = event.clientY; clientX = event.clientX; } return { clientX, clientY }; }; const handleDragStart = (event) => { initData.dragging = true; initData.isClick = true; const { clientX, clientY } = getClientXY(event); if (props.direction === "v") { initData.startY = clientY; } else { initData.startX = clientX; } initData.startPosition = Number.parseFloat(currentPosition.value); initData.newPosition = initData.startPosition; }; const handleDragging = (event) => { if (initData.dragging) { initData.isClick = false; resetSize(); let diff; const { clientX, clientY } = getClientXY(event); if (props.direction === "v") { initData.currentY = clientY; diff = (initData.startY - initData.currentY) / sliderSize.value * 100; } else { initData.currentX = clientX; diff = (initData.currentX - initData.startX) / sliderSize.value * 100; } initData.newPosition = initData.startPosition + diff; setPosition(initData.newPosition); } }; const handleDragEnd = () => { if (initData.dragging) { setTimeout(() => { initData.dragging = false; if (!initData.isClick) { setPosition(initData.newPosition); } emitChange(); }, 0); window.removeEventListener("mousemove", handleDragging); window.removeEventListener("touchmove", handleDragging); window.removeEventListener("mouseup", handleDragEnd); window.removeEventListener("touchend", handleDragEnd); window.removeEventListener("contextmenu", handleDragEnd); } }; const clamp = (num, lower, upper) => { return Math.max(lower, Math.min(num, upper)); }; const setPosition = async (newPosition) => { if (newPosition === null || Number.isNaN(+newPosition)) { return; } newPosition = clamp(newPosition, 0, 100); const fullSteps = Math.floor((max.value - min.value) / step.value); const fullRangePercentage = fullSteps * step.value / (max.value - min.value) * 100; const threshold = fullRangePercentage + (100 - fullRangePercentage) / 2; let value; if (newPosition < fullRangePercentage) { const valueBetween = fullRangePercentage / fullSteps; const steps = Math.round(newPosition / valueBetween); value = min.value + steps * step.value; } else if (newPosition < threshold) { value = min.value + fullSteps * step.value; } else { value = max.value; } value = Number.parseFloat(value.toFixed()); if (value !== props.modelValue) { emit("update:modelValue", value); } if (!initData.dragging && props.modelValue !== initData.oldValue) { initData.oldValue = props.modelValue; } }; watch( () => initData.dragging, (val) => { updateDragging(val); } ); onMounted(() => { var _a; (_a = button.value) == null ? void 0 : _a.addEventListener("touchstart", onButtonDown, { passive: false }); }); onUnmounted(() => { var _a; (_a = button.value) == null ? void 0 : _a.removeEventListener("touchstart", onButtonDown); }); __expose({ onButtonDown, onKeyDown, setPosition, hovering, dragging }); return (_ctx, _cache) => { return openBlock(), createElementBlock( Fragment, null, [ createElementVNode("div", { ref_key: "button", ref: button, class: normalizeClass(["o-slider-btn-wrap", { "o-slider-btn-wrap-hover": showToolTip.value && !props.showSolidCircle && !unref(disabled) }]), style: normalizeStyle(wrapperStyle.value), tabindex: unref(disabled) ? void 0 : 0, onMouseenter: handleMouseEnter, onMouseleave: handleMouseLeave, onMousedown: onButtonDown, onFocus: handleMouseEnter, onBlur: handleMouseLeave, onKeydown: onKeyDown }, [ createElementVNode( "div", { class: normalizeClass(["o-slider-btn", { "o-slider-btn-hover": showToolTip.value && !props.showSolidCircle && !unref(disabled) }]) }, [ props.showSolidCircle ? (openBlock(), createElementBlock("div", _hoisted_2)) : createCommentVNode("v-if", true) ], 2 /* CLASS */ ) ], 46, _hoisted_1), _ctx.showPopover ? (openBlock(), createBlock(unref(OPopover), { key: 0, trigger: "none", position: props.position, visible: showToolTip.value && !unref(disabled), "adjust-width": false, "adjust-min-width": false, target: button.value, wrapper: button.value, "wrap-class": unref(mergeClass)("o-slider-popover", props.wrapClass) }, { default: withCtx(() => [ createTextVNode( toDisplayString(formatValue.value), 1 /* TEXT */ ) ]), _: 1 /* STABLE */ }, 8, ["position", "visible", "target", "wrapper", "wrap-class"])) : createCommentVNode("v-if", true) ], 64 /* STABLE_FRAGMENT */ ); }; } }); export { _sfc_main as default };