@front-ui/use-ripple
Version:
This hook is used to add ripple effect in all elements except void elements
93 lines (91 loc) • 3.17 kB
JavaScript
"use client";
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
useRipple: () => useRipple
});
module.exports = __toCommonJS(src_exports);
var import_react = require("react");
var useRipple = (props = {
duration: 500,
timingFunction: "cubic-bezier(.42,.36,.28,.88)",
disabled: false,
completedFactor: 0.5
}) => {
const ref = (0, import_react.useRef)(null);
const { disabled, duration, completedFactor } = props;
const event = (0, import_react.useCallback)((event2) => {
if (!ref.current || disabled || event2.button !== 0)
return;
const target = ref.current;
requestAnimationFrame(() => {
const begun = Date.now();
const ripple = createRipple(target, event2, props);
target.appendChild(ripple);
const removeRipple = () => {
const now = Date.now();
const diff = now - begun;
setTimeout(
() => {
ripple.style.opacity = "0";
ripple.addEventListener("transitionend", (e) => {
if (e.propertyName === "opacity")
ripple.remove();
});
},
diff > completedFactor * duration ? 0 : completedFactor * duration - diff
);
};
document.addEventListener("pointerup", removeRipple, { once: true });
});
}, []);
return [ref, event];
};
var createRipple = (target, event, options) => {
const { clientX, clientY } = event;
const { height, width, top, left } = target.getBoundingClientRect();
const maxHeight = Math.max(clientY - top, height - clientY + top);
const maxWidth = Math.max(clientX - left, width - clientX + left);
const size = Math.hypot(maxHeight, maxWidth) * 2;
const element = document.createElement("span");
const { duration, timingFunction } = options;
element.style.cssText = `
position: absolute;
top: ${event.clientY - top}px;
left: ${event.clientX - left}px;
height: ${size}px;
width: ${size}px;
translate: -50% -50%;
pointer-events: none;
border-radius: 50%;
background-color: var(--rippleBg);
scale: 0;
transition: scale ${duration}ms ${timingFunction}, opacity ${duration * 0.7}ms ease-in-out;
`;
requestAnimationFrame(() => {
element.style.scale = "1";
});
return element;
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
useRipple
});