Initial commit: expo-popcore-app
This commit is contained in:
116
components/ui/button.tsx
Normal file
116
components/ui/button.tsx
Normal file
@@ -0,0 +1,116 @@
|
||||
import * as React from "react";
|
||||
import { Pressable, Text, type PressableProps, type ViewStyle } from "react-native";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
const buttonVariants = cva(
|
||||
"flex-row items-center justify-center rounded-md active:opacity-70",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary",
|
||||
destructive: "bg-destructive",
|
||||
outline: "border border-input bg-background",
|
||||
secondary: "bg-secondary",
|
||||
ghost: "active:bg-accent",
|
||||
link: "",
|
||||
gradient: "",
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-4 py-2",
|
||||
sm: "h-9 px-3",
|
||||
lg: "h-11 px-8",
|
||||
icon: "h-10 w-10",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const buttonTextVariants = cva("text-sm font-medium text-center", {
|
||||
variants: {
|
||||
variant: {
|
||||
default: "text-primary-foreground",
|
||||
destructive: "text-destructive-foreground",
|
||||
outline: "text-foreground",
|
||||
secondary: "text-secondary-foreground",
|
||||
ghost: "text-foreground",
|
||||
link: "text-primary",
|
||||
gradient: "text-white",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
});
|
||||
|
||||
export interface ButtonProps
|
||||
extends Omit<PressableProps, "style">,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
children?: React.ReactNode;
|
||||
style?: ViewStyle;
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<
|
||||
React.ElementRef<typeof Pressable>,
|
||||
ButtonProps
|
||||
>(({ className, variant, size, children, disabled, style, ...props }, ref) => {
|
||||
const isGradient = variant === "gradient";
|
||||
|
||||
const content = typeof children === "string" ? (
|
||||
<Text className={cn(buttonTextVariants({ variant }))}>{children}</Text>
|
||||
) : (
|
||||
children
|
||||
);
|
||||
|
||||
// 合并样式,确保 borderRadius 正确应用
|
||||
const borderRadius = style?.borderRadius ?? (isGradient ? 12 : undefined);
|
||||
const mergedStyle = borderRadius
|
||||
? [style, { borderRadius }]
|
||||
: style;
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
ref={ref}
|
||||
className={cn(
|
||||
buttonVariants({ variant, size }),
|
||||
disabled && "opacity-50",
|
||||
isGradient && "overflow-hidden",
|
||||
className
|
||||
)}
|
||||
disabled={disabled}
|
||||
style={mergedStyle}
|
||||
{...props}
|
||||
>
|
||||
{isGradient ? (
|
||||
<LinearGradient
|
||||
colors={["#9966FF", "#FF6699", "#FF9966"]}
|
||||
locations={[0.0015, 0.4985, 0.9956]}
|
||||
start={{ x: 1, y: 0 }}
|
||||
end={{ x: 0, y: 0 }}
|
||||
style={{
|
||||
flex: 1,
|
||||
alignSelf: "stretch",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
borderRadius: borderRadius ?? 12,
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
</LinearGradient>
|
||||
) : (
|
||||
content
|
||||
)}
|
||||
</Pressable>
|
||||
);
|
||||
});
|
||||
|
||||
Button.displayName = "Button";
|
||||
|
||||
export { Button, buttonVariants };
|
||||
Reference in New Issue
Block a user