Untitled

mail@pastecode.io avatar
unknown
plain_text
a month ago
3.4 kB
3
Indexable
Never
import React from "react";
import styles from "./button.module.scss";


type ButtonVariants = "standard" | "outline" | "icon-outline" | "icon-filled";
type ButtonColorSchema = "primary" | "secondary";
type ButtonSize = "sm" | "md" | "lg";
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>{
    children: React.ReactNode;
    variant: ButtonVariants,
    colorSchema?: ButtonColorSchema,
    size?: ButtonSize,
}


enum ButtonStates{
    IDLE,
    ANIMATING
}

enum MouseStates
{
     IDLE,
     PRESSING,
}
enum TransitionStates {
    IDLE,
    FORWARD,
    FORWARD_END,
    BACKWARD
}

type MouseButtonStates = {
    button: ButtonStates;
    mouse: MouseStates;
    transition: TransitionStates
};

export default function Button({children, variant="standard", colorSchema="primary", size="md"}:ButtonProps): React.ReactElement{
    const buttonRef: React.MutableRefObject<HTMLButtonElement | null> = React.useRef<HTMLButtonElement | null>(null);
    const states:React.MutableRefObject<MouseButtonStates> = React.useRef<MouseButtonStates>(
        {
            button: ButtonStates.IDLE,
            mouse: MouseStates.IDLE,
            transition: TransitionStates.IDLE
        }
    );
    const press = (): void =>{
        buttonRef.current!.classList.add(styles.press);
        states.current.button = ButtonStates.ANIMATING;
        states.current.transition = TransitionStates.FORWARD
    }

    const release = ():void =>{
        buttonRef.current!.classList.remove(styles.press);
        states.current.transition = TransitionStates.BACKWARD;
    }
    const onMouseDown = (): void =>{
        states.current.mouse = MouseStates.PRESSING;
        if(states.current.button === ButtonStates.IDLE){
            press();
        }
    };
    const onMouseUp = (): void =>{
        states.current.mouse = MouseStates.IDLE;
        if(states.current.transition === TransitionStates.FORWARD_END){
            release();
        }
    };

    const onTransitionEnd = (event: React.TransitionEvent<HTMLButtonElement>): void =>{
        if (event.propertyName === "scale"){
            if(states.current.transition !== TransitionStates.BACKWARD){
                states.current.transition = TransitionStates.FORWARD_END;
                if(states.current.mouse === MouseStates.IDLE){
                    release();
                }
            }
            else{
                states.current.transition = TransitionStates.IDLE;
                states.current.button = ButtonStates.IDLE;
                if(states.current.mouse === MouseStates.PRESSING){
                  press()
                }
            }

        }
    };

    const onMouseLeave = ()=>{
        states.current.mouse = MouseStates.IDLE;
        if(states.current.button === ButtonStates.ANIMATING && states.current.transition === TransitionStates.FORWARD_END){
            release();
        }
    }
    return (
        <button
            ref={buttonRef}
            onMouseDown={onMouseDown}
            onMouseUp={onMouseUp}
            onTransitionEnd={onTransitionEnd}
            onMouseLeave={onMouseLeave}
            className={[styles['button'], styles[variant], styles[colorSchema], styles[size]].join(" ")}
        >
            {children}
        </button>
    )
}
Leave a Comment