You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
433 lines
12 KiB
433 lines
12 KiB
"use client";
|
|
import React = require("react");
|
|
import { ActivityIndicator, Pressable, Text, View } from "react-native";
|
|
|
|
const SCOPE = "BUTTON";
|
|
|
|
const Root = withStyleContext(Pressable, SCOPE);
|
|
|
|
const UIButton = createButton({
|
|
Root: Root,
|
|
Text,
|
|
Group: View,
|
|
Spinner: ActivityIndicator,
|
|
Icon: UIIcon,
|
|
});
|
|
|
|
cssInterop(PrimitiveIcon, {
|
|
className: {
|
|
target: "style",
|
|
nativeStyleToProp: {
|
|
height: true,
|
|
width: true,
|
|
fill: true,
|
|
color: "classNameColor",
|
|
stroke: true,
|
|
},
|
|
},
|
|
});
|
|
|
|
const buttonStyle = tva({
|
|
base: "group/button rounded-3xl bg-primary-500 flex-row items-center justify-center data-[focus-visible=true]:web:outline-none data-[focus-visible=true]:web:ring-2 data-[disabled=true]:opacity-40 gap-2",
|
|
variants: {
|
|
action: {
|
|
primary:
|
|
"bg-primary-500 data-[hover=true]:bg-primary-600 data-[active=true]:bg-primary-700 border-primary-300 data-[hover=true]:border-primary-400 data-[active=true]:border-primary-500 data-[focus-visible=true]:web:ring-indicator-info",
|
|
secondary:
|
|
"bg-secondary-500 border-secondary-300 data-[hover=true]:bg-secondary-600 data-[hover=true]:border-secondary-400 data-[active=true]:bg-secondary-700 data-[active=true]:border-secondary-700 data-[focus-visible=true]:web:ring-indicator-info",
|
|
positive:
|
|
"bg-success-500 border-success-300 data-[hover=true]:bg-success-600 data-[hover=true]:border-success-400 data-[active=true]:bg-success-700 data-[active=true]:border-success-500 data-[focus-visible=true]:web:ring-indicator-info",
|
|
negative:
|
|
"bg-error-500 border-error-300 data-[hover=true]:bg-error-600 data-[hover=true]:border-error-400 data-[active=true]:bg-error-700 data-[active=true]:border-error-500 data-[focus-visible=true]:web:ring-indicator-info",
|
|
default:
|
|
"bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent",
|
|
},
|
|
variant: {
|
|
link: "px-0",
|
|
outline:
|
|
"bg-transparent border data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent",
|
|
solid: "",
|
|
},
|
|
|
|
size: {
|
|
xs: "h-8",
|
|
sm: "h-9",
|
|
md: "h-10",
|
|
lg: "h-11",
|
|
xl: "p-4 h-16",
|
|
"2xl": "p-6 h-20",
|
|
"3xl": "p-8 h-24",
|
|
},
|
|
},
|
|
compoundVariants: [
|
|
{
|
|
action: "primary",
|
|
variant: "link",
|
|
class:
|
|
"px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent",
|
|
},
|
|
{
|
|
action: "secondary",
|
|
variant: "link",
|
|
class:
|
|
"px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent",
|
|
},
|
|
{
|
|
action: "positive",
|
|
variant: "link",
|
|
class:
|
|
"px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent",
|
|
},
|
|
{
|
|
action: "negative",
|
|
variant: "link",
|
|
class:
|
|
"px-0 bg-transparent data-[hover=true]:bg-transparent data-[active=true]:bg-transparent",
|
|
},
|
|
{
|
|
action: "primary",
|
|
variant: "outline",
|
|
class:
|
|
"bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent",
|
|
},
|
|
{
|
|
action: "secondary",
|
|
variant: "outline",
|
|
class:
|
|
"bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent",
|
|
},
|
|
{
|
|
action: "positive",
|
|
variant: "outline",
|
|
class:
|
|
"bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent",
|
|
},
|
|
{
|
|
action: "negative",
|
|
variant: "outline",
|
|
class:
|
|
"bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent",
|
|
},
|
|
],
|
|
});
|
|
|
|
const buttonTextStyle = tva({
|
|
base: "text-typography-0 font-semibold web:select-none",
|
|
parentVariants: {
|
|
action: {
|
|
primary:
|
|
"text-primary-600 data-[hover=true]:text-primary-600 data-[active=true]:text-primary-700",
|
|
secondary:
|
|
"text-typography-500 data-[hover=true]:text-typography-600 data-[active=true]:text-typography-700",
|
|
positive:
|
|
"text-success-600 data-[hover=true]:text-success-600 data-[active=true]:text-success-700",
|
|
negative:
|
|
"text-error-600 data-[hover=true]:text-error-600 data-[active=true]:text-error-700",
|
|
},
|
|
variant: {
|
|
link: "underline data-[hover=true]:underline data-[active=true]:underline text-orange-400",
|
|
outline: "",
|
|
solid:
|
|
"text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0",
|
|
},
|
|
size: {
|
|
xs: "text-xs",
|
|
sm: "text-sm",
|
|
md: "text-base",
|
|
lg: "text-lg",
|
|
xl: "text-xl",
|
|
"2xl": "text-2xl",
|
|
"3xl": "text-3xl",
|
|
},
|
|
},
|
|
parentCompoundVariants: [
|
|
{
|
|
variant: "solid",
|
|
action: "primary",
|
|
class:
|
|
"text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0",
|
|
},
|
|
{
|
|
variant: "solid",
|
|
action: "secondary",
|
|
class:
|
|
"text-typography-800 data-[hover=true]:text-typography-800 data-[active=true]:text-typography-800",
|
|
},
|
|
{
|
|
variant: "solid",
|
|
action: "positive",
|
|
class:
|
|
"text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0",
|
|
},
|
|
{
|
|
variant: "solid",
|
|
action: "negative",
|
|
class:
|
|
"text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0",
|
|
},
|
|
{
|
|
variant: "outline",
|
|
action: "primary",
|
|
class:
|
|
"text-primary-500 data-[hover=true]:text-primary-500 data-[active=true]:text-primary-500",
|
|
},
|
|
{
|
|
variant: "outline",
|
|
action: "secondary",
|
|
class:
|
|
"text-typography-500 data-[hover=true]:text-primary-600 data-[active=true]:text-typography-700",
|
|
},
|
|
{
|
|
variant: "outline",
|
|
action: "positive",
|
|
class:
|
|
"text-primary-500 data-[hover=true]:text-primary-500 data-[active=true]:text-primary-500",
|
|
},
|
|
{
|
|
variant: "outline",
|
|
action: "negative",
|
|
class:
|
|
"text-primary-500 data-[hover=true]:text-primary-500 data-[active=true]:text-primary-500",
|
|
},
|
|
],
|
|
});
|
|
|
|
const buttonIconStyle = tva({
|
|
base: "fill-none",
|
|
parentVariants: {
|
|
variant: {
|
|
link: "data-[hover=true]:underline data-[active=true]:underline",
|
|
outline: "",
|
|
solid:
|
|
"text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0",
|
|
},
|
|
size: {
|
|
xs: "h-3.5 w-3.5",
|
|
sm: "h-4 w-4",
|
|
md: "h-[18px] w-[18px]",
|
|
lg: "h-[18px] w-[18px]",
|
|
xl: "h-5 w-5",
|
|
"2xl": "h-8 w-8",
|
|
"3xl": "h-10 w-10",
|
|
},
|
|
action: {
|
|
primary:
|
|
"text-primary-600 data-[hover=true]:text-primary-600 data-[active=true]:text-primary-700",
|
|
secondary:
|
|
"text-typography-500 data-[hover=true]:text-typography-600 data-[active=true]:text-typography-700",
|
|
positive:
|
|
"text-success-600 data-[hover=true]:text-success-600 data-[active=true]:text-success-700",
|
|
|
|
negative:
|
|
"text-error-600 data-[hover=true]:text-error-600 data-[active=true]:text-error-700",
|
|
},
|
|
},
|
|
parentCompoundVariants: [
|
|
{
|
|
variant: "solid",
|
|
action: "primary",
|
|
class:
|
|
"text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0",
|
|
},
|
|
{
|
|
variant: "solid",
|
|
action: "secondary",
|
|
class:
|
|
"text-typography-800 data-[hover=true]:text-typography-800 data-[active=true]:text-typography-800",
|
|
},
|
|
{
|
|
variant: "solid",
|
|
action: "positive",
|
|
class:
|
|
"text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0",
|
|
},
|
|
{
|
|
variant: "solid",
|
|
action: "negative",
|
|
class:
|
|
"text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0",
|
|
},
|
|
],
|
|
});
|
|
|
|
const buttonGroupStyle = tva({
|
|
base: "",
|
|
variants: {
|
|
space: {
|
|
xs: "gap-1",
|
|
sm: "gap-2",
|
|
md: "gap-3",
|
|
lg: "gap-4",
|
|
xl: "gap-5",
|
|
"2xl": "gap-6",
|
|
"3xl": "gap-7",
|
|
"4xl": "gap-8",
|
|
},
|
|
isAttached: {
|
|
true: "gap-0",
|
|
},
|
|
flexDirection: {
|
|
row: "flex-row",
|
|
column: "flex-col",
|
|
"row-reverse": "flex-row-reverse",
|
|
"column-reverse": "flex-col-reverse",
|
|
},
|
|
},
|
|
});
|
|
|
|
type IButtonProps = Omit<
|
|
React.ComponentPropsWithoutRef<typeof UIButton>,
|
|
"context"
|
|
> &
|
|
VariantProps<typeof buttonStyle> & { className?: string };
|
|
|
|
const Button = React.forwardRef<
|
|
React.ElementRef<typeof UIButton>,
|
|
IButtonProps
|
|
>(
|
|
(
|
|
{ className, variant = "solid", size = "md", action = "primary", ...props },
|
|
ref
|
|
) => {
|
|
return (
|
|
<UIButton
|
|
ref={ref}
|
|
{...props}
|
|
className={buttonStyle({ variant, size, action, class: className })}
|
|
context={{ variant, size, action }}
|
|
/>
|
|
);
|
|
}
|
|
);
|
|
|
|
type IButtonTextProps = React.ComponentPropsWithoutRef<typeof UIButton.Text> &
|
|
VariantProps<typeof buttonTextStyle> & { className?: string };
|
|
|
|
const ButtonText = React.forwardRef<
|
|
React.ElementRef<typeof UIButton.Text>,
|
|
IButtonTextProps
|
|
>(({ className, variant, size, action, ...props }, ref) => {
|
|
const {
|
|
variant: parentVariant,
|
|
size: parentSize,
|
|
action: parentAction,
|
|
} = useStyleContext(SCOPE);
|
|
|
|
return (
|
|
<UIButton.Text
|
|
ref={ref}
|
|
{...props}
|
|
className={buttonTextStyle({
|
|
parentVariants: {
|
|
variant: parentVariant,
|
|
size: parentSize,
|
|
action: parentAction,
|
|
},
|
|
variant,
|
|
size,
|
|
action,
|
|
class: className,
|
|
})}
|
|
/>
|
|
);
|
|
});
|
|
|
|
const ButtonSpinner = UIButton.Spinner;
|
|
|
|
type IButtonIcon = React.ComponentPropsWithoutRef<typeof UIButton.Icon> &
|
|
VariantProps<typeof buttonIconStyle> & {
|
|
className?: string | undefined;
|
|
as?: React.ElementType;
|
|
height?: number;
|
|
width?: number;
|
|
};
|
|
|
|
const ButtonIcon = React.forwardRef<
|
|
React.ElementRef<typeof UIButton.Icon>,
|
|
IButtonIcon
|
|
>(({ className, size, ...props }, ref) => {
|
|
const {
|
|
variant: parentVariant,
|
|
size: parentSize,
|
|
action: parentAction,
|
|
} = useStyleContext(SCOPE);
|
|
|
|
if (typeof size === "number") {
|
|
return (
|
|
<UIButton.Icon
|
|
ref={ref}
|
|
{...props}
|
|
className={buttonIconStyle({ class: className })}
|
|
size={size}
|
|
/>
|
|
);
|
|
} else if (
|
|
(props.height !== undefined || props.width !== undefined) &&
|
|
size === undefined
|
|
) {
|
|
return (
|
|
<UIButton.Icon
|
|
ref={ref}
|
|
{...props}
|
|
className={buttonIconStyle({ class: className })}
|
|
/>
|
|
);
|
|
}
|
|
return (
|
|
<UIButton.Icon
|
|
{...props}
|
|
className={buttonIconStyle({
|
|
parentVariants: {
|
|
size: parentSize,
|
|
variant: parentVariant,
|
|
action: parentAction,
|
|
},
|
|
size,
|
|
class: className,
|
|
})}
|
|
ref={ref}
|
|
/>
|
|
);
|
|
});
|
|
|
|
type IButtonGroupProps = React.ComponentPropsWithoutRef<typeof UIButton.Group> &
|
|
VariantProps<typeof buttonGroupStyle>;
|
|
|
|
const ButtonGroup = React.forwardRef<
|
|
React.ElementRef<typeof UIButton.Group>,
|
|
IButtonGroupProps
|
|
>(
|
|
(
|
|
{
|
|
className,
|
|
space = "md",
|
|
isAttached = false,
|
|
flexDirection = "column",
|
|
...props
|
|
},
|
|
ref
|
|
) => {
|
|
return (
|
|
<UIButton.Group
|
|
className={buttonGroupStyle({
|
|
class: className,
|
|
space,
|
|
isAttached,
|
|
flexDirection,
|
|
})}
|
|
{...props}
|
|
ref={ref}
|
|
/>
|
|
);
|
|
}
|
|
);
|
|
|
|
Button.displayName = "Button";
|
|
ButtonText.displayName = "ButtonText";
|
|
ButtonSpinner.displayName = "ButtonSpinner";
|
|
ButtonIcon.displayName = "ButtonIcon";
|
|
ButtonGroup.displayName = "ButtonGroup";
|
|
|
|
export { Button, ButtonText, ButtonSpinner, ButtonIcon, ButtonGroup };
|
|
export type ButtonActions = keyof typeof buttonStyle.variants.action;
|