| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- import "./toast.css";
- interface ToastOptions {
- html: string;
- displayLength: number;
- inDuration: number;
- outDuration: number;
- classes: string;
- completeCallback?: (toast: Toast) => void;
- activationPercent: number;
- }
- const defaultOptions: ToastOptions = {
- html: "",
- displayLength: 4000,
- inDuration: 300,
- outDuration: 375,
- classes: "",
- activationPercent: 0.7,
- };
- export class Toast {
- static _container: HTMLElement | null = null;
- static _toasts: Array<Toast> = [];
- element: HTMLElement;
- options: ToastOptions;
- isMoving: boolean;
- startTime: number;
- startingPosX: number;
- get activationDistance(): number {
- return this.element.offsetWidth * this.options.activationPercent;
- }
- constructor(options: Partial<ToastOptions>) {
- this.options = { ...defaultOptions, ...options };
- if (Toast._container == null) {
- Toast._createContainer();
- }
- this.startTime = Date.now();
- this.startingPosX = 0;
- this.isMoving = false;
- this.element = document.createElement("div");
- this.element.className = "toast " + this.options.classes;
- this.element.innerHTML = this.options.html;
- const onDragStart = (e: MouseEvent | TouchEvent) => {
- e.stopPropagation();
- this.startingPosX = this._getposX(e);
- this.element.style.transition = "all 0s";
- this.isMoving = true;
- document.addEventListener("touchmove", onDragMove);
- document.addEventListener("touchend", onDragEnd);
- document.addEventListener("mousemove", onDragMove);
- document.addEventListener("mouseup", onDragEnd);
- };
- const onDragMove = (e: MouseEvent | TouchEvent) => {
- e.stopPropagation();
- const totalDeltaX = this._getposX(e) - this.startingPosX;
- this.element.style.transform = `translateX(${totalDeltaX}px)`;
- this.element.style.opacity = "" + (1 - Math.abs(totalDeltaX / this.activationDistance));
- };
- const onDragEnd = (e: MouseEvent | TouchEvent) => {
- const totalDeltaX = this.startingPosX - this._getposX(e);
- this.isMoving = false;
- // Remove toast
- if (Math.abs(totalDeltaX) > this.activationDistance) {
- this.dismiss();
- // Animate toast back to original position
- } else {
- this.element.style.transition = "transform .2s, opacity .2s";
- this.element.style.transform = "";
- this.element.style.opacity = "";
- }
- document.removeEventListener("touchmove", onDragMove);
- document.removeEventListener("touchend", onDragEnd);
- document.removeEventListener("mousemove", onDragMove);
- document.removeEventListener("mouseup", onDragEnd);
- };
- this.element.addEventListener("touchstart", onDragStart);
- this.element.addEventListener("mousedown", onDragStart);
- this.element.style.top = `30px`;
- this.element.style.opacity = `0`;
- this.element.style.transition = `top ${this.options.inDuration}ms, opacity ${this.options.inDuration}ms`;
- if (this.options.displayLength < Infinity) {
- this.update();
- }
- Toast._container?.appendChild(this.element);
- setTimeout(() => {
- this.element.style.top = `0px`;
- this.element.style.opacity = `1`;
- }, 10);
- Toast._toasts.push(this);
- }
- update(): void {
- const ellapsed = Date.now() - this.startTime;
- if (this.options && ellapsed < this.options.displayLength) {
- this.element.style.setProperty(
- "--completion",
- Math.round((ellapsed / this.options.displayLength) * 100) + "%"
- );
- setTimeout(() => this.update(), 20);
- } else {
- this.dismiss();
- }
- }
- _getposX(e: MouseEvent | TouchEvent): number {
- if (e instanceof MouseEvent) {
- return e.clientX;
- } else {
- return e.touches[0].clientX;
- }
- }
- dismiss(): void {
- this.element.style.transition = `all ${this.options.outDuration}ms`;
- this.element.style.marginTop = `-${this.element.offsetHeight}px`;
- this.element.style.opacity = "0";
- setTimeout(() => {
- Toast._container?.removeChild(this.element);
- Toast._toasts = Toast._toasts.filter((e) => e !== this);
- if (Toast._toasts.length === 0) {
- Toast._removeContainer();
- }
- if (this.options.completeCallback) this.options.completeCallback(this);
- }, this.options.outDuration);
- }
- static dismissAll(): void {
- for (const toastIndex in Toast._toasts) {
- Toast._toasts[toastIndex].dismiss();
- }
- }
- static _createContainer(): void {
- const container = document.createElement("div");
- container.setAttribute("id", "toast-container");
- document.body.appendChild(container);
- Toast._container = container;
- }
- static _removeContainer(): void {
- if (Toast._container) {
- document.body.removeChild(Toast._container);
- Toast._container = null;
- }
- }
- }
- export default function (options: Partial<ToastOptions>): Toast {
- return new Toast(options);
- }
|