205 lines
6.7 KiB
TypeScript
205 lines
6.7 KiB
TypeScript
|
import {
|
||
|
AnchorHTMLAttributes,
|
||
|
ButtonHTMLAttributes,
|
||
|
DetailedHTMLProps,
|
||
|
HTMLAttributeAnchorTarget,
|
||
|
HTMLAttributes,
|
||
|
} from "react";
|
||
|
import { twMerge } from "tailwind-merge";
|
||
|
import Loading from "../elements/Loading";
|
||
|
|
||
|
/**
|
||
|
* # Buttons
|
||
|
* @className twui-button-general
|
||
|
* @className twui-button-content-wrapper
|
||
|
* @className twui-button-primary
|
||
|
* @className twui-button-primary-outlined
|
||
|
* @className twui-button-primary-ghost
|
||
|
* @className twui-button-secondary
|
||
|
* @className twui-button-secondary-outlined
|
||
|
* @className twui-button-secondary-ghost
|
||
|
* @className twui-button-accent
|
||
|
* @className twui-button-accent-outlined
|
||
|
* @className twui-button-accent-ghost
|
||
|
* @className twui-button-gray
|
||
|
* @className twui-button-gray-outlined
|
||
|
* @className twui-button-gray-ghost
|
||
|
*/
|
||
|
export default function Button({
|
||
|
href,
|
||
|
target,
|
||
|
variant,
|
||
|
color,
|
||
|
size,
|
||
|
buttonContentProps,
|
||
|
linkProps,
|
||
|
beforeIcon,
|
||
|
afterIcon,
|
||
|
loading,
|
||
|
...props
|
||
|
}: DetailedHTMLProps<
|
||
|
ButtonHTMLAttributes<HTMLButtonElement>,
|
||
|
HTMLButtonElement
|
||
|
> & {
|
||
|
variant?: "normal" | "ghost" | "outlined";
|
||
|
color?:
|
||
|
| "primary"
|
||
|
| "secondary"
|
||
|
| "accent"
|
||
|
| "gray"
|
||
|
| "error"
|
||
|
| "warning"
|
||
|
| "success";
|
||
|
size?: "small" | "smaller" | "normal" | "large" | "larger";
|
||
|
href?: string;
|
||
|
target?: HTMLAttributeAnchorTarget;
|
||
|
loading?: boolean;
|
||
|
linkProps?: DetailedHTMLProps<
|
||
|
AnchorHTMLAttributes<HTMLAnchorElement>,
|
||
|
HTMLAnchorElement
|
||
|
>;
|
||
|
beforeIcon?: React.ReactNode;
|
||
|
afterIcon?: React.ReactNode;
|
||
|
buttonContentProps?: DetailedHTMLProps<
|
||
|
HTMLAttributes<HTMLDivElement>,
|
||
|
HTMLDivElement
|
||
|
>;
|
||
|
}) {
|
||
|
const finalClassName: string = (() => {
|
||
|
if (variant == "normal" || !variant) {
|
||
|
if (color == "primary" || !color)
|
||
|
return twMerge(
|
||
|
"bg-blue-500 hover:bg-blue-600 text-white",
|
||
|
"twui-button-primary"
|
||
|
);
|
||
|
if (color == "secondary")
|
||
|
return twMerge(
|
||
|
"bg-emerald-500 hover:bg-emerald-600 text-white",
|
||
|
"twui-button-secondary"
|
||
|
);
|
||
|
if (color == "accent")
|
||
|
return twMerge(
|
||
|
"bg-violet-500 hover:bg-violet-600 text-white",
|
||
|
"twui-button-accent"
|
||
|
);
|
||
|
if (color == "gray")
|
||
|
return twMerge(
|
||
|
"bg-slate-300 hover:bg-slate-200 text-slate-800",
|
||
|
"twui-button-gray"
|
||
|
);
|
||
|
} else if (variant == "outlined") {
|
||
|
if (color == "primary" || !color)
|
||
|
return twMerge(
|
||
|
"bg-transparent outline outline-1 outline-blue-500",
|
||
|
"text-blue-500 dark:text-blue-400 dark:outline-blue-300",
|
||
|
"twui-button-primary-outlined"
|
||
|
);
|
||
|
if (color == "secondary")
|
||
|
return twMerge(
|
||
|
"bg-transparent outline outline-1 outline-emerald-500",
|
||
|
"text-emerald-500",
|
||
|
"twui-button-secondary-outlined"
|
||
|
);
|
||
|
if (color == "accent")
|
||
|
return twMerge(
|
||
|
"bg-transparent outline outline-1 outline-violet-500",
|
||
|
"text-violet-500",
|
||
|
"twui-button-accent-outlined"
|
||
|
);
|
||
|
if (color == "gray")
|
||
|
return twMerge(
|
||
|
"bg-transparent outline outline-1 outline-slate-300",
|
||
|
"text-slate-600 dark:text-white/60 dark:outline-white/30",
|
||
|
"twui-button-gray-outlined"
|
||
|
);
|
||
|
} else if (variant == "ghost") {
|
||
|
if (color == "primary" || !color)
|
||
|
return twMerge(
|
||
|
"bg-transparent outline-none p-2",
|
||
|
"text-blue-500",
|
||
|
"twui-button-primary-ghost"
|
||
|
);
|
||
|
if (color == "secondary")
|
||
|
return twMerge(
|
||
|
"bg-transparent outline-none p-2",
|
||
|
"text-emerald-500",
|
||
|
"twui-button-secondary-ghost"
|
||
|
);
|
||
|
if (color == "accent")
|
||
|
return twMerge(
|
||
|
"bg-transparent outline-none p-2",
|
||
|
"text-violet-500",
|
||
|
"twui-button-accent-ghost"
|
||
|
);
|
||
|
if (color == "gray")
|
||
|
return twMerge(
|
||
|
"bg-transparent outline-none p-2",
|
||
|
"text-slate-600 dark:text-white/70",
|
||
|
"twui-button-gray-ghost"
|
||
|
);
|
||
|
if (color == "error")
|
||
|
return twMerge(
|
||
|
"bg-transparent outline-none p-2",
|
||
|
"text-red-600 dark:text-red-400",
|
||
|
"twui-button-error-ghost"
|
||
|
);
|
||
|
if (color == "warning")
|
||
|
return twMerge(
|
||
|
"bg-transparent outline-none p-2",
|
||
|
"text-yellow-600",
|
||
|
"twui-button-warning-ghost"
|
||
|
);
|
||
|
if (color == "success")
|
||
|
return twMerge(
|
||
|
"bg-transparent outline-none p-2",
|
||
|
"text-emerald-600",
|
||
|
"twui-button-success-ghost"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return "";
|
||
|
})();
|
||
|
|
||
|
const buttonComponent = (
|
||
|
<button
|
||
|
{...props}
|
||
|
className={twMerge(
|
||
|
"bg-blue-600 text-white text-base font-medium px-4 py-2 rounded",
|
||
|
"flex items-center justify-center relative transition-all",
|
||
|
"twui-button-general",
|
||
|
size == "small" && "px-3 py-1.5 text-sm",
|
||
|
size == "smaller" && "px-2 py-1 text-xs",
|
||
|
size == "large" && "text-lg",
|
||
|
size == "larger" && "px-5 py-3 text-xl",
|
||
|
finalClassName,
|
||
|
props.className,
|
||
|
loading ? "pointer-events-none opacity-80" : "l"
|
||
|
)}
|
||
|
>
|
||
|
<div
|
||
|
{...buttonContentProps}
|
||
|
className={twMerge(
|
||
|
"flex flex-row items-center gap-2",
|
||
|
loading ? "opacity-0" : "",
|
||
|
"twui-button-content-wrapper",
|
||
|
buttonContentProps?.className
|
||
|
)}
|
||
|
>
|
||
|
{beforeIcon && beforeIcon}
|
||
|
{props.children}
|
||
|
{afterIcon && afterIcon}
|
||
|
</div>
|
||
|
|
||
|
{loading && <Loading className="absolute" />}
|
||
|
</button>
|
||
|
);
|
||
|
|
||
|
if (href)
|
||
|
return (
|
||
|
<a {...linkProps} href={href} target={target}>
|
||
|
{buttonComponent}
|
||
|
</a>
|
||
|
);
|
||
|
return buttonComponent;
|
||
|
}
|