133 lines
3.7 KiB
TypeScript

import { type AsChild, Slot, type VariantProps, vcn } from "@pswui-lib";
import React from "react";
const colors = {
disabled:
"disabled:brightness-50 disabled:cursor-not-allowed disabled:opacity-50 disabled:saturate-50",
outline: {
focus: "dark:focus-visible:outline-white/20 focus-visible:outline-black/10",
},
border: {
default: "border-neutral-300 dark:border-neutral-700",
success: "border-green-400 dark:border-green-600",
warning: "border-yellow-400 dark:border-yellow-600",
danger: "border-red-400 dark:border-red-600",
},
background: {
default:
"bg-white dark:bg-black hover:bg-neutral-200 dark:hover:bg-neutral-800",
ghost:
"bg-black/0 dark:bg-white/0 hover:bg-black/20 dark:hover:bg-white/20",
success:
"bg-green-100 dark:bg-green-900 hover:bg-green-200 dark:hover:bg-green-800",
warning:
"bg-yellow-100 dark:bg-yellow-900 hover:bg-yellow-200 dark:hover:bg-yellow-800",
danger: "bg-red-100 dark:bg-red-900 hover:bg-red-200 dark:hover:bg-red-800",
},
underline: "decoration-current",
};
const [buttonVariants, resolveVariants] = vcn({
base: `w-fit flex flex-row items-center justify-between rounded-md outline outline-1 outline-transparent outline-offset-2 ${colors.outline.focus} ${colors.disabled} transition-all cursor-pointer`,
variants: {
size: {
link: "p-0 text-base",
sm: "px-2 py-1 text-sm",
md: "px-4 py-2 text-base",
lg: "px-5 py-3 text-lg",
icon: "p-2 text-base",
},
border: {
none: "border-0",
solid: `border ${colors.border.default}`,
success: `border ${colors.border.success}`,
warning: `border ${colors.border.warning}`,
danger: `border ${colors.border.danger}`,
},
background: {
default: colors.background.default,
ghost: colors.background.ghost,
success: colors.background.success,
warning: colors.background.warning,
danger: colors.background.danger,
transparent: "bg-transparent hover:bg-transparent",
},
decoration: {
none: "no-underline",
link: `underline decoration-1 underline-offset-2 hover:underline-offset-4 ${colors.underline}`,
},
},
defaults: {
size: "md",
border: "solid",
background: "default",
decoration: "none",
},
presets: {
default: {
border: "solid",
background: "default",
decoration: "none",
size: "md",
},
ghost: {
border: "none",
background: "ghost",
decoration: "none",
size: "md",
},
link: {
border: "none",
background: "transparent",
decoration: "link",
size: "link",
},
success: {
border: "success",
background: "success",
decoration: "none",
size: "md",
},
warning: {
border: "warning",
background: "warning",
decoration: "none",
size: "md",
},
danger: {
border: "danger",
background: "danger",
decoration: "none",
size: "md",
},
},
});
export interface ButtonProps
extends Omit<React.ComponentPropsWithoutRef<"button">, "className">,
VariantProps<typeof buttonVariants>,
AsChild {}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
(props, ref) => {
const [variantProps, otherPropsCompressed] = resolveVariants(props);
const { asChild, type, role, ...otherPropsExtracted } =
otherPropsCompressed;
const Comp = asChild ? Slot : "button";
return (
<Comp
ref={ref}
type={type ?? "button"}
className={buttonVariants(variantProps)}
role={role ?? "button"}
{...otherPropsExtracted}
/>
);
},
);
Button.displayName = "Button";
export { Button };