@poupe/vue
Version:
Vue component library for Poupe UI framework with theme customization and accessibility support
77 lines (73 loc) • 2.2 kB
JavaScript
import { onMounted, onUnmounted, ref, unref } from "vue";
export function useRipple(elementReference, options = {}) {
const { color = "currentColor", opacity = .12, duration = 600, bounded = true, disabled = false } = options;
const ripples = ref([]);
let rippleId = 0;
const addRipple = (event) => {
if (unref(disabled) || !elementReference.value) return;
const element = elementReference.value;
const rect = element.getBoundingClientRect();
let x;
let y;
if (event instanceof MouseEvent) {
x = event.clientX - rect.left;
y = event.clientY - rect.top;
} else {
const touch = event.touches[0];
if (!touch) return;
x = touch.clientX - rect.left;
y = touch.clientY - rect.top;
}
const sizeX = Math.max(x, rect.width - x);
const sizeY = Math.max(y, rect.height - y);
const size = Math.hypot(sizeX, sizeY) * 2;
const id = rippleId++;
const ripple = {
x,
y,
size,
id
};
ripples.value.push(ripple);
setTimeout(() => {
ripples.value = ripples.value.filter((r) => r.id !== id);
}, duration);
};
const handleMouseDown = (event) => {
addRipple(event);
};
const handleTouchStart = (event) => {
addRipple(event);
};
onMounted(() => {
if (!elementReference.value || unref(disabled)) return;
elementReference.value.addEventListener("mousedown", handleMouseDown);
elementReference.value.addEventListener("touchstart", handleTouchStart, { passive: true });
elementReference.value.style.position = "relative";
elementReference.value.style.overflow = bounded ? "hidden" : "visible";
});
onUnmounted(() => {
if (!elementReference.value) return;
elementReference.value.removeEventListener("mousedown", handleMouseDown);
elementReference.value.removeEventListener("touchstart", handleTouchStart);
});
const getRippleStyle = (ripple) => {
return {
position: "absolute",
left: `${ripple.x}px`,
top: `${ripple.y}px`,
width: `${ripple.size}px`,
height: `${ripple.size}px`,
transform: "translate(-50%, -50%)",
borderRadius: "50%",
backgroundColor: color,
opacity,
pointerEvents: "none",
animation: `ripple ${duration}ms ease-out`
};
};
return {
ripples,
getRippleStyle
};
}