282 lines
6.8 KiB
TypeScript
282 lines
6.8 KiB
TypeScript
import React from "react";
|
|
import { styled } from "../stitches.config";
|
|
import Flex from "./Flex";
|
|
import Spinner from "./Spinner";
|
|
|
|
export const StyledButton = styled("button", {
|
|
// Reset
|
|
all: "unset",
|
|
position: "relative",
|
|
appereance: "none",
|
|
fontFamily: "$body",
|
|
alignItems: "center",
|
|
boxSizing: "border-box",
|
|
userSelect: "none",
|
|
"&::before": {
|
|
boxSizing: "border-box",
|
|
},
|
|
"&::after": {
|
|
boxSizing: "border-box",
|
|
},
|
|
// Custom reset?
|
|
display: "inline-flex",
|
|
flexShrink: 0,
|
|
justifyContent: "center",
|
|
lineHeight: "1",
|
|
gap: "5px",
|
|
WebkitTapHighlightColor: "rgba(0,0,0,0)",
|
|
// Custom
|
|
height: "$6",
|
|
px: "$2",
|
|
fontSize: "$2",
|
|
fontWeight: 500,
|
|
fontVariantNumeric: "tabular-nums",
|
|
cursor: "pointer",
|
|
width: "max-content",
|
|
"&:disabled": {
|
|
opacity: 0.6,
|
|
pointerEvents: "none",
|
|
cursor: "not-allowed",
|
|
},
|
|
variants: {
|
|
size: {
|
|
xs: {
|
|
borderRadius: "$sm",
|
|
height: "$5",
|
|
px: "$2",
|
|
fontSize: "$xs",
|
|
},
|
|
sm: {
|
|
borderRadius: "$sm",
|
|
height: "$7",
|
|
px: "$3",
|
|
fontSize: "$xs",
|
|
},
|
|
md: {
|
|
borderRadius: "$sm",
|
|
height: "$8",
|
|
px: "$3",
|
|
fontSize: "$xs",
|
|
},
|
|
lg: {
|
|
borderRadius: "$sm",
|
|
height: "$10",
|
|
px: "$4",
|
|
fontSize: "$xs",
|
|
},
|
|
},
|
|
variant: {
|
|
link: {
|
|
textDecoration: "underline",
|
|
fontSize: "inherit",
|
|
color: "$textMuted",
|
|
textUnderlineOffset: "2px",
|
|
},
|
|
default: {
|
|
backgroundColor: "$mauve12",
|
|
boxShadow: "inset 0 0 0 1px $colors$mauve12",
|
|
color: "$mauve1",
|
|
"@hover": {
|
|
"&:hover": {
|
|
backgroundColor: "$mauve12",
|
|
boxShadow: "inset 0 0 0 1px $colors$mauve12",
|
|
},
|
|
},
|
|
"&:active": {
|
|
backgroundColor: "$mauve10",
|
|
boxShadow: "inset 0 0 0 1px $colors$mauve11",
|
|
},
|
|
"&:focus": {
|
|
boxShadow:
|
|
"inset 0 0 0 1px $colors$mauve12, inset 0 0 0 2px $colors$mauve12",
|
|
},
|
|
'&[data-radix-popover-trigger][data-state="open"], &[data-radix-dropdown-menu-trigger][data-state="open"]':
|
|
{
|
|
backgroundColor: "$mauve4",
|
|
boxShadow: "inset 0 0 0 1px $colors$mauve8",
|
|
},
|
|
},
|
|
primary: {
|
|
backgroundColor: `$accent`,
|
|
boxShadow: "inset 0 0 0 1px $colors$purple9",
|
|
color: "$white",
|
|
"@hover": {
|
|
"&:hover": {
|
|
backgroundColor: "$purple10",
|
|
boxShadow: "inset 0 0 0 1px $colors$purple11",
|
|
},
|
|
},
|
|
"&:active": {
|
|
backgroundColor: "$purple8",
|
|
boxShadow: "inset 0 0 0 1px $colors$purple8",
|
|
},
|
|
"&:focus": {
|
|
boxShadow: "inset 0 0 0 2px $colors$purple12",
|
|
},
|
|
'&[data-radix-popover-trigger][data-state="open"], &[data-radix-dropdown-menu-trigger][data-state="open"]':
|
|
{
|
|
backgroundColor: "$mauve4",
|
|
boxShadow: "inset 0 0 0 1px $colors$purple8",
|
|
},
|
|
},
|
|
secondary: {
|
|
backgroundColor: `$purple9`,
|
|
boxShadow: "inset 0 0 0 1px $colors$purple9",
|
|
color: "$white",
|
|
"@hover": {
|
|
"&:hover": {
|
|
backgroundColor: "$purple10",
|
|
boxShadow: "inset 0 0 0 1px $colors$purple11",
|
|
},
|
|
},
|
|
"&:active": {
|
|
backgroundColor: "$purple8",
|
|
boxShadow: "inset 0 0 0 1px $colors$purple8",
|
|
},
|
|
"&:focus": {
|
|
boxShadow: "inset 0 0 0 2px $colors$purple12",
|
|
},
|
|
'&[data-radix-popover-trigger][data-state="open"], &[data-radix-dropdown-menu-trigger][data-state="open"]':
|
|
{
|
|
backgroundColor: "$mauve4",
|
|
boxShadow: "inset 0 0 0 1px $colors$purple8",
|
|
},
|
|
},
|
|
destroy: {
|
|
backgroundColor: `$red9`,
|
|
boxShadow: "inset 0 0 0 1px $colors$red9",
|
|
color: "$white",
|
|
"@hover": {
|
|
"&:hover": {
|
|
backgroundColor: "$red10",
|
|
boxShadow: "inset 0 0 0 1px $colors$red11",
|
|
},
|
|
},
|
|
"&:active": {
|
|
backgroundColor: "$red8",
|
|
boxShadow: "inset 0 0 0 1px $colors$red8",
|
|
},
|
|
"&:focus": {
|
|
boxShadow: "inset 0 0 0 2px $colors$red12",
|
|
},
|
|
'&[data-radix-popover-trigger][data-state="open"], &[data-radix-dropdown-menu-trigger][data-state="open"]':
|
|
{
|
|
backgroundColor: "$mauve4",
|
|
boxShadow: "inset 0 0 0 1px $colors$red8",
|
|
},
|
|
},
|
|
},
|
|
muted: {
|
|
true: {
|
|
color: "$textMuted",
|
|
},
|
|
},
|
|
outline: {
|
|
true: {
|
|
backgroundColor: "transparent",
|
|
},
|
|
},
|
|
uppercase: {
|
|
true: {
|
|
textTransform: "uppercase",
|
|
},
|
|
},
|
|
fullWidth: {
|
|
true: {
|
|
width: "100%",
|
|
},
|
|
},
|
|
ghost: {
|
|
true: {
|
|
boxShadow: "none",
|
|
background: "transparent",
|
|
color: "$mauve12",
|
|
"@hover": {
|
|
"&:hover": {
|
|
backgroundColor: "$mauve6",
|
|
boxShadow: "none",
|
|
},
|
|
},
|
|
"&:active": {
|
|
backgroundColor: "$mauve8",
|
|
boxShadow: "none",
|
|
},
|
|
"&:focus": {
|
|
boxShadow: "none",
|
|
},
|
|
},
|
|
},
|
|
isLoading: {
|
|
true: {
|
|
"& .button-content": {
|
|
visibility: "hidden",
|
|
},
|
|
pointerEvents: "none",
|
|
},
|
|
},
|
|
},
|
|
compoundVariants: [
|
|
{
|
|
outline: true,
|
|
variant: "default",
|
|
css: {
|
|
background: "transparent",
|
|
color: "$mauve12",
|
|
boxShadow: "inset 0 0 0 1px $colors$mauve10",
|
|
"&:hover": {
|
|
color: "$mauve12",
|
|
background: "$mauve5",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
outline: true,
|
|
variant: "primary",
|
|
css: {
|
|
background: "transparent",
|
|
color: "$mauve12",
|
|
"&:hover": {
|
|
color: "$mauve12",
|
|
background: "$mauve5",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
outline: true,
|
|
variant: "secondary",
|
|
css: {
|
|
background: "transparent",
|
|
color: "$mauve12",
|
|
"&:hover": {
|
|
color: "$mauve12",
|
|
background: "$mauve5",
|
|
},
|
|
},
|
|
},
|
|
],
|
|
defaultVariants: {
|
|
size: "md",
|
|
variant: "default",
|
|
},
|
|
});
|
|
|
|
const CustomButton: React.FC<
|
|
React.ComponentProps<typeof StyledButton> & { as?: string }
|
|
> = React.forwardRef(({ children, as = "button", ...rest }, ref) => (
|
|
// @ts-expect-error
|
|
<StyledButton {...rest} ref={ref} as={as}>
|
|
<Flex
|
|
as="span"
|
|
css={{ gap: "$2", alignItems: "center" }}
|
|
className="button-content"
|
|
>
|
|
{children}
|
|
</Flex>
|
|
{rest.isLoading && <Spinner css={{ position: "absolute" }} />}
|
|
</StyledButton>
|
|
));
|
|
|
|
CustomButton.displayName = "CustomButton";
|
|
|
|
export default CustomButton;
|