@opensig/opendesign
Version:
300 lines (299 loc) • 9.89 kB
JavaScript
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
};