mm
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import {
|
||||
type ComponentPropsWithoutRef,
|
||||
forwardRef,
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
|
||||
import { Icon } from "../Icon/Icon";
|
||||
import { SpinnerSvg } from "../../assets/svg/SpinnerSvg";
|
||||
import { cpm } from "../../styles/utils/cpm";
|
||||
import { itemSizeRecipe } from "../../recipes/itemSizeRecipe";
|
||||
import { variantRecipe } from "../../recipes/variantRecipe";
|
||||
import { brandRecipe } from "../../recipes/brandRecipe";
|
||||
import { inlineSizeRecipe } from "../../recipes/inlineSizeRecipe";
|
||||
|
||||
export type ButtonSize = "xs" | "sm" | "md" | "lg";
|
||||
|
||||
export type ButtonProps = ComponentPropsWithoutRef<"button"> & {
|
||||
size?: ButtonSize;
|
||||
variant?: "filled" | "outline" | "subtle" | "ghost";
|
||||
shape?: "rounded" | "square" | "circle";
|
||||
brand?: "success" | "danger" | "info" | "warning" | "emphasize";
|
||||
} & {
|
||||
iconOnly?: boolean;
|
||||
hideIcon?: boolean;
|
||||
loading?: boolean;
|
||||
} & {
|
||||
iconSvg?: ReactNode;
|
||||
loadingIconSvg?: ReactNode;
|
||||
};
|
||||
|
||||
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
(props, ref) => {
|
||||
const {
|
||||
size = "md",
|
||||
variant = "filled",
|
||||
shape = "rounded",
|
||||
brand = "info",
|
||||
// ===========================
|
||||
iconOnly = false,
|
||||
hideIcon = false,
|
||||
loading,
|
||||
disabled = false,
|
||||
// =========================
|
||||
className = "",
|
||||
children,
|
||||
// ==========================
|
||||
iconSvg,
|
||||
loadingIconSvg = <SpinnerSvg />,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const mergedClass = cpm(
|
||||
itemSizeRecipe({ size, shape, iconOnly }),
|
||||
variantRecipe({ variant, disabled }),
|
||||
brandRecipe({ brand }),
|
||||
className,
|
||||
);
|
||||
|
||||
const contentClass = loading
|
||||
? cpm("visible--hidden", inlineSizeRecipe({ size }))
|
||||
: inlineSizeRecipe({ size });
|
||||
|
||||
const loadingIconClass = loading ? "position--absolute" : "";
|
||||
|
||||
const icon = <Icon size={size}>{iconSvg}</Icon>;
|
||||
const loadingIcon = (
|
||||
<Icon className={loadingIconClass} size={size}>
|
||||
{loadingIconSvg}
|
||||
</Icon>
|
||||
);
|
||||
|
||||
return (
|
||||
<button ref={ref} className={mergedClass} disabled={disabled} {...rest}>
|
||||
<span className={contentClass}>
|
||||
{!hideIcon && iconSvg && icon}
|
||||
{!iconOnly && children}
|
||||
</span>
|
||||
{loading && loadingIcon}
|
||||
</button>
|
||||
);
|
||||
},
|
||||
);
|
||||
Button.displayName = "Button";
|
||||
Reference in New Issue
Block a user