mirror of
https://github.com/rio-labs/rio.git
synced 2026-02-08 23:00:39 -06:00
103 lines
3.0 KiB
TypeScript
103 lines
3.0 KiB
TypeScript
import { commitCss } from "./utils";
|
|
|
|
class RippleEffectOptions {
|
|
rippleDuration?: number;
|
|
rippleCssColor?: string;
|
|
triggerOnPress?: boolean;
|
|
customCss?: { [attr: string]: string };
|
|
}
|
|
|
|
export class RippleEffect {
|
|
public customCss: { [attr: string]: string };
|
|
|
|
private element: HTMLElement;
|
|
|
|
private rippleDuration: number;
|
|
private rippleCssColor: string;
|
|
|
|
private boundEventHandler: (event: MouseEvent) => void;
|
|
|
|
constructor(
|
|
element: HTMLElement,
|
|
{
|
|
rippleDuration = 0.9,
|
|
rippleCssColor = "var(--rio-local-text-color)",
|
|
triggerOnPress = true,
|
|
customCss = {},
|
|
}: RippleEffectOptions = {}
|
|
) {
|
|
this.element = element;
|
|
this.rippleDuration = rippleDuration;
|
|
this.rippleCssColor = rippleCssColor;
|
|
this.customCss = customCss;
|
|
|
|
// Subscribe to events
|
|
if (triggerOnPress) {
|
|
this.boundEventHandler = this.trigger.bind(this);
|
|
this.element.addEventListener("click", this.boundEventHandler);
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
if (this.boundEventHandler !== undefined) {
|
|
this.element.removeEventListener("click", this.boundEventHandler);
|
|
}
|
|
}
|
|
|
|
trigger(event: MouseEvent) {
|
|
// Find the ripple's origin
|
|
const rect = this.element.getBoundingClientRect();
|
|
const x = event.clientX - rect.left;
|
|
const y = event.clientY - rect.top;
|
|
|
|
// Spawn two elements: one for the animation, and one with `overflow:
|
|
// hidden`
|
|
let rippleContainer = document.createElement("div");
|
|
rippleContainer.classList.add(
|
|
"rio-ripple-container",
|
|
"rio-not-a-child-component"
|
|
);
|
|
rippleContainer.style.setProperty(
|
|
"--rio-ripple-color",
|
|
this.rippleCssColor
|
|
);
|
|
rippleContainer.style.setProperty(
|
|
"--rio-ripple-duration",
|
|
`${this.rippleDuration}s`
|
|
);
|
|
Object.assign(rippleContainer.style, this.customCss);
|
|
this.element.appendChild(rippleContainer);
|
|
|
|
let rippleElement = document.createElement("div");
|
|
rippleElement.classList.add("rio-ripple-effect");
|
|
rippleContainer.appendChild(rippleElement);
|
|
|
|
// Position it
|
|
rippleElement.style.top = `${y}px`;
|
|
rippleElement.style.left = `${x}px`;
|
|
|
|
rippleElement.style.width = "0px";
|
|
rippleElement.style.height = "0px";
|
|
|
|
rippleElement.style.opacity = "0.1";
|
|
|
|
// Commit CSS
|
|
commitCss(rippleElement);
|
|
|
|
// Animate it
|
|
rippleElement.style.top = `${rect.height / 2}px`;
|
|
rippleElement.style.left = `${rect.width / 2}px`;
|
|
|
|
let size = Math.max(rect.width, rect.height) * 2;
|
|
rippleElement.style.width = `${size}px`;
|
|
rippleElement.style.height = `${size}px`;
|
|
|
|
rippleElement.style.opacity = "0";
|
|
|
|
// Remove the ripple element after the animation
|
|
setTimeout(() => {
|
|
rippleContainer.remove();
|
|
}, this.rippleDuration * 1000);
|
|
}
|
|
}
|