mirror of
https://github.com/hanzo-io/team.git
synced 2026-10-30 18:56:23 +00:00
134 lines
4.1 KiB
TypeScript
134 lines
4.1 KiB
TypeScript
import * as Slot from '@rn-primitives/slot';
|
|
import { cva, type VariantProps } from 'class-variance-authority';
|
|
import * as React from 'react';
|
|
import { Platform, Pressable, PressableProps, View, ViewStyle } from 'react-native';
|
|
import { TextClassContext } from '@components/nativewindui/Text';
|
|
import { cn } from '@lib/cn';
|
|
import { useColorScheme } from '@hooks/useColorScheme';
|
|
import { COLORS } from '@theme/colors';
|
|
|
|
const buttonVariants = cva('flex-row items-center justify-center gap-2', {
|
|
variants: {
|
|
variant: {
|
|
primary: 'active:opacity-80 bg-primary',
|
|
secondary: 'border-primary active:bg-primary/5 border',
|
|
tonal:
|
|
'bg-primary/10 dark:bg-primary/10 active:bg-primary/15',
|
|
plain: 'active:opacity-70',
|
|
},
|
|
size: {
|
|
none: '',
|
|
sm: 'py-1 px-2.5 rounded-full',
|
|
md: 'rounded-lg py-1.5 px-3.5',
|
|
lg: 'px-5 py-2 rounded-xl gap-2',
|
|
icon: 'rounded-lg h-10 w-10',
|
|
},
|
|
},
|
|
defaultVariants: {
|
|
variant: 'primary',
|
|
size: 'md',
|
|
},
|
|
});
|
|
|
|
const buttonTextVariants = cva('font-medium', {
|
|
variants: {
|
|
variant: {
|
|
primary: 'text-white',
|
|
secondary: 'ios:text-primary text-foreground',
|
|
tonal: 'ios:text-primary text-foreground',
|
|
plain: 'text-foreground',
|
|
},
|
|
size: {
|
|
none: '',
|
|
icon: '',
|
|
sm: 'text-[15px] leading-5',
|
|
md: 'text-[17px] leading-7',
|
|
lg: 'text-[17px] leading-7',
|
|
},
|
|
},
|
|
defaultVariants: {
|
|
variant: 'primary',
|
|
size: 'md',
|
|
},
|
|
});
|
|
|
|
function convertToRGBA(rgb: string, opacity: number): string {
|
|
const rgbValues = rgb.match(/\d+/g);
|
|
if (!rgbValues || rgbValues.length !== 3) {
|
|
throw new Error('Invalid RGB color format');
|
|
}
|
|
const red = parseInt(rgbValues[0], 10);
|
|
const green = parseInt(rgbValues[1], 10);
|
|
const blue = parseInt(rgbValues[2], 10);
|
|
if (opacity < 0 || opacity > 1) {
|
|
throw new Error('Opacity must be a number between 0 and 1');
|
|
}
|
|
return `rgba(${red},${green},${blue},${opacity})`;
|
|
}
|
|
|
|
const ANDROID_RIPPLE = {
|
|
dark: {
|
|
primary: { color: convertToRGBA(COLORS.dark.grey3, 0.4), borderless: false },
|
|
secondary: { color: convertToRGBA(COLORS.dark.grey5, 0.8), borderless: false },
|
|
plain: { color: convertToRGBA(COLORS.dark.grey5, 0.8), borderless: false },
|
|
tonal: { color: convertToRGBA(COLORS.dark.grey5, 0.8), borderless: false },
|
|
},
|
|
light: {
|
|
primary: { color: convertToRGBA(COLORS.light.grey4, 0.4), borderless: false },
|
|
secondary: { color: convertToRGBA(COLORS.light.grey5, 0.4), borderless: false },
|
|
plain: { color: convertToRGBA(COLORS.light.grey5, 0.4), borderless: false },
|
|
tonal: { color: convertToRGBA(COLORS.light.grey6, 0.4), borderless: false },
|
|
},
|
|
};
|
|
|
|
// Add as class when possible: https://github.com/marklawlor/nativewind/issues/522
|
|
const BORDER_CURVE: ViewStyle = {
|
|
borderCurve: 'continuous',
|
|
};
|
|
|
|
type ButtonVariantProps = Omit<VariantProps<typeof buttonVariants>, 'variant'> & {
|
|
variant?: Exclude<VariantProps<typeof buttonVariants>['variant'], null>;
|
|
};
|
|
|
|
type AndroidOnlyButtonProps = {
|
|
/**
|
|
* ANDROID ONLY: The class name of root responsible for hidding the ripple overflow.
|
|
*/
|
|
androidRootClassName?: string;
|
|
};
|
|
|
|
type ButtonProps = PressableProps & ButtonVariantProps & AndroidOnlyButtonProps;
|
|
|
|
const Root = Platform.OS === 'android' ? View : Slot.Pressable;
|
|
|
|
const Button = React.forwardRef<React.ElementRef<typeof Pressable>, ButtonProps>(
|
|
(
|
|
{ className, variant = 'primary', size, style = BORDER_CURVE, androidRootClassName, ...props },
|
|
ref
|
|
) => {
|
|
const { colorScheme } = useColorScheme();
|
|
|
|
return (
|
|
<TextClassContext.Provider value={buttonTextVariants({ variant, size })}>
|
|
<Root>
|
|
<Pressable
|
|
className={cn(
|
|
props.disabled && 'opacity-50',
|
|
buttonVariants({ variant, size, className })
|
|
)}
|
|
ref={ref}
|
|
style={style}
|
|
android_ripple={ANDROID_RIPPLE[colorScheme][variant]}
|
|
{...props}
|
|
/>
|
|
</Root>
|
|
</TextClassContext.Provider>
|
|
);
|
|
}
|
|
);
|
|
|
|
Button.displayName = 'Button';
|
|
|
|
export { Button, buttonTextVariants, buttonVariants };
|
|
export type { ButtonProps };
|