parent
c31fb48123
commit
77b250a52f
@ -0,0 +1,66 @@
|
||||
import LoginForm from "@/components/form/LoginForm";
|
||||
import Button from "@/components/ui/Button";
|
||||
import Screen from "@/components/ui/Screen";
|
||||
import Text from "@/components/ui/Text";
|
||||
import { Feather } from "@expo/vector-icons";
|
||||
import { Link } from "expo-router";
|
||||
import { View } from "react-native";
|
||||
|
||||
export default function LoginPage() {
|
||||
interface ISocialNetworkButtons {
|
||||
icon: any;
|
||||
}
|
||||
const socialNetworkButtons: ISocialNetworkButtons[] = [
|
||||
{ icon: "instagram" },
|
||||
{ icon: "facebook" },
|
||||
{ icon: "linkedin" },
|
||||
];
|
||||
|
||||
return (
|
||||
<Screen>
|
||||
<View className="justify-center gap-4 h-full">
|
||||
<View className="gap-2">
|
||||
<Text position="center" size="3xl" weight="bold">
|
||||
Connexion à Optifit
|
||||
</Text>
|
||||
<Text position="center" size="xl">
|
||||
Personnalise ton expérience du sport avec Optifit, ton nouveau coach
|
||||
IA.
|
||||
</Text>
|
||||
</View>
|
||||
<LoginForm />
|
||||
<View className="flex-row justify-center gap-4">
|
||||
{socialNetworkButtons.map((socialNetworkButton) => (
|
||||
<Button
|
||||
className="w-[4.5rem] h-[4.5rem]"
|
||||
key={socialNetworkButton.icon}
|
||||
size="xl"
|
||||
style="outline"
|
||||
>
|
||||
<Feather
|
||||
name={socialNetworkButton.icon}
|
||||
size={26}
|
||||
color={"black"}
|
||||
/>
|
||||
</Button>
|
||||
))}
|
||||
</View>
|
||||
<View className="gap-2">
|
||||
<Text position="center">
|
||||
Tu n'as pas encore de compte ?{" "}
|
||||
<Link href="/sign-in">
|
||||
<Text weight="bold" isLink={true}>
|
||||
Inscris-toi !
|
||||
</Text>
|
||||
</Link>
|
||||
</Text>
|
||||
<Link href="/reset-password">
|
||||
<Text position="center" weight="bold" isLink={true}>
|
||||
Mot de passe oublié ?
|
||||
</Text>
|
||||
</Link>
|
||||
</View>
|
||||
</View>
|
||||
</Screen>
|
||||
);
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
import Screen from "@/components/ui/Screen";
|
||||
import CustomText from "@/components/ui/Text";
|
||||
import { Link } from "expo-router";
|
||||
import { View } from "react-native";
|
||||
|
||||
const socialNetworkButtons: ISocialNetworkButtons[] = [
|
||||
{ icon: "instagram" },
|
||||
{ icon: "facebook" },
|
||||
{ icon: "linkedin" },
|
||||
];
|
||||
|
||||
interface ISocialNetworkButtons {
|
||||
icon: any;
|
||||
}
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
<Screen>
|
||||
<View className="flex flex-col gap-4">
|
||||
<View className="flex flex-col gap-2">
|
||||
<CustomText center={true} size="3xl" bold={true}>
|
||||
Connexion à Optifit
|
||||
</CustomText>
|
||||
<CustomText center={true} size="lg">
|
||||
Personnalise ton expérience du sport avec Optifit, ton nouveau coach
|
||||
IA.
|
||||
</CustomText>
|
||||
</View>
|
||||
{/* <LoginForm /> */}
|
||||
<View className="flex flex-col gap-2">
|
||||
<CustomText center={true}>
|
||||
Tu n'as pas encore de compte ?
|
||||
<Link href="/(auth)/sign-in">
|
||||
<CustomText bold={true} isLink={true}>
|
||||
{" "}
|
||||
Inscris-toi !
|
||||
</CustomText>
|
||||
</Link>
|
||||
</CustomText>
|
||||
<Link href="/reset-password">
|
||||
<CustomText center={true} bold={true} isLink={true}>
|
||||
Mot de passe oublié ?
|
||||
</CustomText>
|
||||
</Link>
|
||||
</View>
|
||||
</View>
|
||||
</Screen>
|
||||
|
||||
// <Screen>
|
||||
// <Box className="h-full justify-center">
|
||||
// <VStack space="2xl">
|
||||
// <VStack space="sm">
|
||||
// <Heading className="text-center" size="3xl">
|
||||
// Connexion à Optifit
|
||||
// </Heading>
|
||||
// <Text size="lg" className="text-center">
|
||||
// Personnalise ton expérience du sport avec Optifit, ton nouveau
|
||||
// coach IA.
|
||||
// </Text>
|
||||
// </VStack>
|
||||
// <LoginForm />
|
||||
// <ButtonGroup className="justify-center" flexDirection="row">
|
||||
// {socialNetworkButtons.map((socialNetworkButton) => (
|
||||
// <Button
|
||||
// key={socialNetworkButton.icon}
|
||||
// size="xl"
|
||||
// variant="outline"
|
||||
// action="primary"
|
||||
// >
|
||||
// <Feather name={socialNetworkButton.icon} size={27} />
|
||||
// </Button>
|
||||
// ))}
|
||||
// </ButtonGroup>
|
||||
// <VStack>
|
||||
// <HStack className="justify-center items-center" space="xs">
|
||||
// <Text>Tu n'as pas encore de compte ?</Text>
|
||||
// <Link href="/(auth)/sign-in">
|
||||
// <LinkText bold={true}>Inscris-toi !</LinkText>
|
||||
// </Link>
|
||||
// </HStack>
|
||||
// <Link className="text-center" href="/reset-password">
|
||||
// <LinkText bold={true}>Mot de passe oublié ?</LinkText>
|
||||
// </Link>
|
||||
// </VStack>
|
||||
// </VStack>
|
||||
// </Box>
|
||||
// </Screen>
|
||||
);
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
import Button from "@/components/ui/Button";
|
||||
import Screen from "@/components/ui/Screen";
|
||||
import Text from "@/components/ui/Text";
|
||||
import TextInput from "@/components/form/FormInput";
|
||||
import BackButton from "@/components/BackButton";
|
||||
import { View } from "react-native";
|
||||
import React from "react";
|
||||
import CodeSent from "@/components/modals/CodeSent";
|
||||
import FormError from "@/components/form/FormError";
|
||||
import { EMPTY_FIELD, INVALID_EMAIL } from "@/components/Errors";
|
||||
import { isEmail } from "validator";
|
||||
|
||||
export default function ResetPasswordWithEmail() {
|
||||
const [isModalVisible, setIsModalVisible] = React.useState(false);
|
||||
const [email, setEmail] = React.useState("");
|
||||
const [error, setError] = React.useState("");
|
||||
const [isFormValid, setIsFormValid] = React.useState(true);
|
||||
|
||||
const validateForm = () => {
|
||||
setError("");
|
||||
setIsFormValid(true);
|
||||
};
|
||||
|
||||
const invalidateForm = (error: string) => {
|
||||
setError(error);
|
||||
setIsFormValid(false);
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
if (email != "") {
|
||||
if (isEmail(email)) {
|
||||
validateForm();
|
||||
setIsModalVisible(true);
|
||||
} else {
|
||||
invalidateForm(INVALID_EMAIL);
|
||||
}
|
||||
} else {
|
||||
invalidateForm(EMPTY_FIELD);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Screen>
|
||||
<CodeSent
|
||||
email={email}
|
||||
onPress={() => setIsModalVisible(false)}
|
||||
visible={isModalVisible}
|
||||
/>
|
||||
<BackButton icon="close" />
|
||||
<View className="gap-4">
|
||||
<Text size="3xl" weight="bold">
|
||||
Recevoir un code par email
|
||||
</Text>
|
||||
<TextInput
|
||||
beforeIcon="mail"
|
||||
placeholder="Test@Optifit.com"
|
||||
onChangeText={setEmail}
|
||||
value={email}
|
||||
label={"Adresse mail"}
|
||||
/>
|
||||
<FormError isVisible={!isFormValid}>{error}</FormError>
|
||||
<Button onPress={onSubmit} afterIcon="arrowright">
|
||||
Recevoir le code
|
||||
</Button>
|
||||
</View>
|
||||
</Screen>
|
||||
);
|
||||
}
|
@ -1,67 +1,49 @@
|
||||
// import {Text} from "@/components/ui/text";
|
||||
// import {
|
||||
// Button,
|
||||
// ButtonGroup,
|
||||
// ButtonIcon,
|
||||
// ButtonText,
|
||||
// } from "@/components/ui/button";
|
||||
// import {VStack} from "@/components/ui/vstack";
|
||||
// import React from "react";
|
||||
// import {
|
||||
// ArrowRightIcon,
|
||||
// LockIcon,
|
||||
// MailIcon,
|
||||
// MessageCircleIcon,
|
||||
// } from "@/components/ui/icon";
|
||||
// import BackButton from "@/components/BackButton";
|
||||
// import Screen from "@/components/Screen";
|
||||
// import {Heading} from "@/components/ui/heading";
|
||||
// import {Link} from "expo-router";
|
||||
// import {SafeAreaView} from "react-native";
|
||||
import BackButton from "@/components/BackButton";
|
||||
import { AntDesignIconNames } from "@/components/Icons";
|
||||
import Button from "@/components/ui/Button";
|
||||
import Screen from "@/components/ui/Screen";
|
||||
import Text from "@/components/ui/Text";
|
||||
import { Link } from "expo-router";
|
||||
import { View } from "react-native";
|
||||
|
||||
// const resetButtons: IResetButton[] = [
|
||||
// {icon: MailIcon, text: "Envoyer par email"},
|
||||
// {icon: LockIcon, text: "Envoyer par 2FA"},
|
||||
// {icon: MessageCircleIcon, text: "Envoyer par SMS"},
|
||||
// ];
|
||||
export default function ResetPasswordPage() {
|
||||
interface IResetButton {
|
||||
icon: AntDesignIconNames;
|
||||
text: string;
|
||||
}
|
||||
|
||||
// interface IResetButton {
|
||||
// icon: React.ElementType;
|
||||
// text: string;
|
||||
// }
|
||||
const resetButtons: IResetButton[] = [
|
||||
{ icon: "mail", text: "Envoyer par email" },
|
||||
{ icon: "lock", text: "Envoyer par 2FA" },
|
||||
{ icon: "message1", text: "Envoyer par SMS" },
|
||||
];
|
||||
|
||||
// export default function ResetPasswordPage() {
|
||||
// return (
|
||||
// <SafeAreaView>
|
||||
// <Screen>
|
||||
// <BackButton link={"/login"}/>
|
||||
// <VStack space="2xl">
|
||||
// <VStack space="sm">
|
||||
// <Heading className="text-center" size="3xl">
|
||||
// Réinitialisation de ton mot de passe
|
||||
// </Heading>
|
||||
// <Text size="lg" className="text-center">
|
||||
// Selectionne une méthode pour recevoir ton code temporaire
|
||||
// </Text>
|
||||
// </VStack>
|
||||
// <ButtonGroup space="xl">
|
||||
// {resetButtons.map((resetButton) => (
|
||||
// <Link key={resetButton.text} href={"/sign-in"} asChild>
|
||||
// <Button
|
||||
// className="justify-between"
|
||||
// size="2xl"
|
||||
// action="primary"
|
||||
// variant="outline"
|
||||
// >
|
||||
// <ButtonIcon as={resetButton.icon}/>
|
||||
// <ButtonText>{resetButton.text}</ButtonText>
|
||||
// <ButtonIcon as={ArrowRightIcon}/>
|
||||
// </Button>
|
||||
// </Link>
|
||||
// ))}
|
||||
// </ButtonGroup>
|
||||
// </VStack>
|
||||
// </Screen>
|
||||
// </SafeAreaView>
|
||||
// );
|
||||
// }
|
||||
return (
|
||||
<Screen>
|
||||
<BackButton />
|
||||
<View className="gap-4">
|
||||
<View className="gap-2">
|
||||
<Text className="text-center" size="3xl" weight="bold">
|
||||
Réinitialisation de ton mot de passe
|
||||
</Text>
|
||||
<Text size="lg" className="text-center">
|
||||
Selectionne une méthode pour recevoir ton code temporaire !
|
||||
</Text>
|
||||
</View>
|
||||
<View className="gap-4">
|
||||
{resetButtons.map((resetButton) => (
|
||||
<Button
|
||||
key={resetButton.text}
|
||||
size="2xl"
|
||||
style="secondary"
|
||||
beforeIcon={resetButton.icon}
|
||||
afterIcon="arrowright"
|
||||
>
|
||||
<Link href="/reset-password-with-email">{resetButton.text}</Link>
|
||||
</Button>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
</Screen>
|
||||
);
|
||||
}
|
||||
|
@ -1,36 +1,31 @@
|
||||
// import { Text } from "@/components/ui/text";
|
||||
// import { VStack } from "@/components/ui/vstack";
|
||||
// import { Box } from "@/components/ui/box";
|
||||
// import { HStack } from "@/components/ui/hstack";
|
||||
// import React from "react";
|
||||
// import SigninForm from "@/components/form/SigninForm";
|
||||
// import Screen from "@/components/Screen";
|
||||
// import { Heading } from "@/components/ui/heading";
|
||||
// import { Link } from "expo-router";
|
||||
// import { LinkText } from "@/components/ui/link";
|
||||
import SigninForm from "@/components/form/SigninForm";
|
||||
import Screen from "@/components/ui/Screen";
|
||||
import Text from "@/components/ui/Text";
|
||||
import { Link } from "expo-router";
|
||||
import { View } from "react-native";
|
||||
|
||||
// export default function SigninPage() {
|
||||
// return (
|
||||
// <Screen>
|
||||
// <Box className="h-full justify-center">
|
||||
// <VStack space="2xl">
|
||||
// <VStack space="sm">
|
||||
// <Heading className="text-center" size="2xl">
|
||||
// Inscris-toi gratuitement
|
||||
// </Heading>
|
||||
// <Text size="lg" className="text-center">
|
||||
// Génère un programme personnalisé en quelques clics et 1 minute !
|
||||
// </Text>
|
||||
// </VStack>
|
||||
// <SigninForm />
|
||||
// <HStack className="justify-center items-center" space="xs">
|
||||
// <Text>Tu as déjà un compte ?</Text>
|
||||
// <Link href="/sign-in">
|
||||
// <LinkText bold={true}>Connectes-toi !</LinkText>
|
||||
// </Link>
|
||||
// </HStack>
|
||||
// </VStack>
|
||||
// </Box>
|
||||
// </Screen>
|
||||
// );
|
||||
// }
|
||||
export default function SigninPage() {
|
||||
return (
|
||||
<Screen>
|
||||
<View className="justify-center h-full gap-4">
|
||||
<View className="gap-2">
|
||||
<Text position="center" size="3xl" weight="bold">
|
||||
Inscris-toi gratuitement
|
||||
</Text>
|
||||
<Text size="xl" position="center">
|
||||
Génère un programme personnalisé en quelques clics et 1 minute !
|
||||
</Text>
|
||||
</View>
|
||||
<SigninForm />
|
||||
<Text position="center">
|
||||
Tu as déjà un compte ?{" "}
|
||||
<Link href="/log-in">
|
||||
<Text isLink={true} weight="bold">
|
||||
Connectes-toi !
|
||||
</Text>
|
||||
</Link>
|
||||
</Text>
|
||||
</View>
|
||||
</Screen>
|
||||
);
|
||||
}
|
||||
|
@ -1,13 +1,24 @@
|
||||
import {SafeAreaView, Text, View} from "react-native";
|
||||
import { SafeAreaView, Text, View } from "react-native";
|
||||
import React from "react";
|
||||
import Button from "@/components/ui/Button";
|
||||
import { useSession } from "@/ctx";
|
||||
import { router } from "expo-router";
|
||||
|
||||
export default function ProfileScreen() {
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<View>
|
||||
<Text className="m-7 font-extrabold">Welcome Screen </Text>
|
||||
<Text>We will do it soon</Text>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
const { signOut } = useSession();
|
||||
|
||||
const disconnect = () => {
|
||||
signOut();
|
||||
router.replace("/log-in");
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<View>
|
||||
<Text className="m-7 font-extrabold">Welcome Screen </Text>
|
||||
<Text>We will do it soon</Text>
|
||||
</View>
|
||||
<Button onPress={disconnect}>Se déconnecter</Button>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
import Text from "@/components/ui/Text";
|
||||
import { View } from "react-native";
|
||||
|
||||
export default function Loading() {
|
||||
return (
|
||||
<View className="justify-center items-center h-full">
|
||||
<Text size="3xl" weight="bold">
|
||||
Chargement en cours
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
@ -1,23 +1,29 @@
|
||||
import { router } from "expo-router";
|
||||
import Button from "./ui/Button";
|
||||
import { TouchableOpacityProps } from "react-native";
|
||||
import { AntDesign } from "@expo/vector-icons";
|
||||
import { Button, ButtonActions } from "./ui/Button";
|
||||
import { Href, Link } from "expo-router";
|
||||
import React from "react";
|
||||
import { AntDesignIconNames } from "./Icons";
|
||||
|
||||
type props = {
|
||||
icon?: any;
|
||||
link: Href;
|
||||
action?: ButtonActions;
|
||||
};
|
||||
|
||||
export default function BackButton({ icon, link, action }: props) {
|
||||
return (
|
||||
<Button className="h-16 w-16 mb-4" action={action ?? "secondary"}>
|
||||
<Link href={link}>
|
||||
<AntDesign
|
||||
name={icon ?? "arrowleft"}
|
||||
size={30}
|
||||
color={action == "primary" ? "white" : "black"}
|
||||
/>
|
||||
</Link>
|
||||
</Button>
|
||||
);
|
||||
interface Props extends TouchableOpacityProps {
|
||||
icon?: AntDesignIconNames;
|
||||
}
|
||||
|
||||
export default React.forwardRef<any, Props>(
|
||||
(props, ref): React.ReactElement => {
|
||||
const { icon, onPress } = props;
|
||||
const defaultOnPress = () => {
|
||||
router.back();
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
className="h-16 w-16 mb-4"
|
||||
onPress={onPress ?? defaultOnPress}
|
||||
{...ref}
|
||||
>
|
||||
<AntDesign name={icon ?? "arrowleft"} size={24} />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -0,0 +1,58 @@
|
||||
export type Size = "xs" | "md" | "lg" | "xl" | "2xl" | "3xl";
|
||||
export type Color = "black" | "white" | "orange" | "red";
|
||||
export type Weight = "thin" | "normal" | "bold" | "extrabold";
|
||||
export type Position = "left" | "center" | "right";
|
||||
|
||||
export function toTextSize(size: Size): string {
|
||||
switch (size) {
|
||||
case "xs":
|
||||
return "text-xs";
|
||||
case "md":
|
||||
return "text-md";
|
||||
case "lg":
|
||||
return "text-lg";
|
||||
case "xl":
|
||||
return "text-xl";
|
||||
case "2xl":
|
||||
return "text-2xl";
|
||||
case "3xl":
|
||||
return "text-3xl";
|
||||
}
|
||||
}
|
||||
|
||||
export function toTextColor(color: Color): string {
|
||||
switch (color) {
|
||||
case "black":
|
||||
return "text-black";
|
||||
case "white":
|
||||
return "text-white";
|
||||
case "orange":
|
||||
return "text-orange-500";
|
||||
case "red":
|
||||
return "text-red-500";
|
||||
}
|
||||
}
|
||||
|
||||
export function toTextWeight(weight: Weight): string {
|
||||
switch (weight) {
|
||||
case "thin":
|
||||
return "font-thin";
|
||||
case "normal":
|
||||
return "font-normal";
|
||||
case "bold":
|
||||
return "font-bold";
|
||||
case "extrabold":
|
||||
return "font-extrabold";
|
||||
}
|
||||
}
|
||||
|
||||
export function toTextPosition(position: Position): string {
|
||||
switch (position) {
|
||||
case "left":
|
||||
return "text-left";
|
||||
case "center":
|
||||
return "text-center";
|
||||
case "right":
|
||||
return "text-right";
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
export const EMPTY_FIELD = "Un des champs est vide !";
|
||||
export const INVALID_EMAIL = "Adresse mail invalide !";
|
||||
export const NOT_MATCHING_PASSWORD = "Les mots de passe sont différents";
|
@ -0,0 +1,3 @@
|
||||
import { AntDesign } from "@expo/vector-icons";
|
||||
|
||||
export type AntDesignIconNames = keyof typeof AntDesign.glyphMap;
|
@ -1,19 +1,29 @@
|
||||
import {
|
||||
FormControlError,
|
||||
FormControlErrorIcon,
|
||||
FormControlErrorText,
|
||||
} from "../ui/form-control";
|
||||
import { AlertCircleIcon } from "../ui/icon";
|
||||
import React from "react";
|
||||
import { View } from "react-native";
|
||||
import Text, { ExtendedTextProps } from "../ui/Text";
|
||||
import { MaterialIcons } from "@expo/vector-icons";
|
||||
|
||||
type props = { text: string };
|
||||
|
||||
export default function FormError({ text }: props) {
|
||||
return (
|
||||
<FormControlError className="mb-2 border-[1px] border-red-500 p-4 rounded-3xl bg-red-100 gap-2">
|
||||
<FormControlErrorIcon as={AlertCircleIcon} />
|
||||
<FormControlErrorText className="text-black font-bold">
|
||||
{text}
|
||||
</FormControlErrorText>
|
||||
</FormControlError>
|
||||
);
|
||||
interface Props extends ExtendedTextProps {
|
||||
isVisible: boolean;
|
||||
}
|
||||
|
||||
export default React.forwardRef<any, Props>(
|
||||
(props, ref): React.ReactElement => {
|
||||
const { isVisible, ...rest } = props;
|
||||
|
||||
const buildClassName = (): string => {
|
||||
return (
|
||||
"flex-row items-center gap-2 bg-red-300 p-4 border-2 border-red-500 rounded-3xl" +
|
||||
" " +
|
||||
(isVisible ? "block" : "hidden")
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<View className={buildClassName()} {...ref}>
|
||||
<MaterialIcons name="error" size={24} color={"red"} />
|
||||
<Text position="center" weight="bold" {...rest} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -0,0 +1,49 @@
|
||||
import React from "react";
|
||||
import { TextInput, TextInputProps, View } from "react-native";
|
||||
import { AntDesignIconNames } from "../Icons";
|
||||
import { AntDesign } from "@expo/vector-icons";
|
||||
import Text from "../ui/Text";
|
||||
export interface FormInputProps extends TextInputProps {
|
||||
afterIcon?: AntDesignIconNames;
|
||||
label: string;
|
||||
}
|
||||
interface Props extends FormInputProps {
|
||||
beforeIcon: AntDesignIconNames;
|
||||
}
|
||||
|
||||
export default React.forwardRef<any, Props>(
|
||||
(props, ref): React.ReactElement => {
|
||||
const {
|
||||
onBlur,
|
||||
onChangeText,
|
||||
value,
|
||||
beforeIcon,
|
||||
afterIcon,
|
||||
label,
|
||||
placeholder,
|
||||
onPress,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<View className="gap-2">
|
||||
<Text weight="bold">{label}</Text>
|
||||
<View className="flex-row items-center gap-2 px-4 py-2 bg-gray-200 rounded-3xl">
|
||||
<AntDesign name={beforeIcon} size={24} />
|
||||
<TextInput
|
||||
className="grow"
|
||||
placeholder={placeholder}
|
||||
onBlur={onBlur}
|
||||
onChangeText={onChangeText}
|
||||
value={value}
|
||||
{...ref}
|
||||
{...rest}
|
||||
/>
|
||||
{afterIcon != null ? (
|
||||
<AntDesign name={afterIcon} size={24} onPress={onPress} />
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
);
|
@ -1,75 +1,72 @@
|
||||
import React from "react";
|
||||
import { Text } from "react-native";
|
||||
import { View, ViewProps } from "react-native";
|
||||
import TextInput from "./FormInput";
|
||||
import Button from "../ui/Button";
|
||||
export default function LoginForm() {
|
||||
const REQUIRED_ERROR = "Au moins un des champs requis est vide !";
|
||||
const [emailValue, setEmailValue] = React.useState("");
|
||||
const [isEmailInvalid, setIsEmailInvalid] = React.useState(false);
|
||||
const [passwordValue, setPasswordValue] = React.useState("");
|
||||
const [isPasswordInvalid, setIsPasswordInvalid] = React.useState(false);
|
||||
const [isFormInvalid, setIsFormInvalid] = React.useState(false);
|
||||
const handleSubmit = () => {
|
||||
//check for empty fields
|
||||
setIsEmailInvalid(emailValue == "");
|
||||
setIsPasswordInvalid(passwordValue == "");
|
||||
setIsFormInvalid(isEmailInvalid || isPasswordInvalid);
|
||||
};
|
||||
import PasswordTextInput from "./SecretTextInput";
|
||||
import React from "react";
|
||||
import { EMPTY_FIELD, INVALID_EMAIL } from "../Errors";
|
||||
import FormError from "./FormError";
|
||||
import { isEmail } from "validator";
|
||||
import { useSession } from "@/ctx";
|
||||
import { router } from "expo-router";
|
||||
|
||||
export default React.forwardRef<any, ViewProps>(
|
||||
(props, ref): React.ReactElement => {
|
||||
const { ...rest } = props;
|
||||
const [email, setEmail] = React.useState("");
|
||||
const [password, setPassword] = React.useState("");
|
||||
const [error, setError] = React.useState("");
|
||||
const [isFormValid, setIsFormValid] = React.useState(true);
|
||||
const { signIn } = useSession();
|
||||
|
||||
const validateForm = () => {
|
||||
setError("");
|
||||
setIsFormValid(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<FormControl className="gap-4" isInvalid={isFormInvalid}>
|
||||
<FormControl isInvalid={isEmailInvalid}>
|
||||
<FormControlLabel>
|
||||
<FormControlLabelText bold={true}>Adresse mail</FormControlLabelText>
|
||||
</FormControlLabel>
|
||||
<Input variant="outline" size="xl">
|
||||
<InputIcon color="black" as={MailIcon} />
|
||||
<InputField
|
||||
value={emailValue}
|
||||
onChangeText={setEmailValue}
|
||||
placeholder="Test@optifit.com"
|
||||
const invalidateForm = (error: string) => {
|
||||
setError(error);
|
||||
setIsFormValid(false);
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
if (email != "") {
|
||||
if (isEmail(email)) {
|
||||
if (password != "") {
|
||||
validateForm();
|
||||
signIn();
|
||||
router.replace("/HomeScreen");
|
||||
} else {
|
||||
invalidateForm(EMPTY_FIELD);
|
||||
}
|
||||
} else {
|
||||
invalidateForm(INVALID_EMAIL);
|
||||
}
|
||||
} else {
|
||||
invalidateForm(EMPTY_FIELD);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="gap-4" {...ref} {...rest}>
|
||||
<View className="gap-4">
|
||||
<TextInput
|
||||
beforeIcon="mail"
|
||||
placeholder="Test@Optifit.com"
|
||||
onChangeText={setEmail}
|
||||
value={email}
|
||||
label={"Adresse mail"}
|
||||
/>
|
||||
</Input>
|
||||
</FormControl>
|
||||
<FormControl isInvalid={isPasswordInvalid}>
|
||||
<FormControlLabel>
|
||||
<FormControlLabelText bold={true}>Mot de passe</FormControlLabelText>
|
||||
</FormControlLabel>
|
||||
<PasswordField value={passwordValue} onChangeText={setPasswordValue} />
|
||||
</FormControl>
|
||||
<VStack>
|
||||
<FormError text={REQUIRED_ERROR} />
|
||||
<Button size="xl" onPress={handleSubmit}>
|
||||
<ButtonText>Se connecter</ButtonText>
|
||||
<ButtonIcon as={ArrowRightIcon} />
|
||||
</Button>
|
||||
</VStack>
|
||||
</FormControl>
|
||||
<FormControl className="gap-4">
|
||||
<FormControl>
|
||||
<FormControlLabel>
|
||||
<FormControlLabelText bold={true}>Adresse mail</FormControlLabelText>
|
||||
</FormControlLabel>
|
||||
<Input variant="outline" size="xl">
|
||||
<InputIcon color="black" as={MailIcon} />
|
||||
<InputField placeholder="Test@optifit.com" />
|
||||
</Input>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormControlLabel>
|
||||
<FormControlLabelText bold={true}>Mot de passe</FormControlLabelText>
|
||||
</FormControlLabel>
|
||||
<PasswordField />
|
||||
</FormControl>
|
||||
<VStack>
|
||||
<FormError text={"REQUIRED_ERROR"} />
|
||||
<Button size="xl">
|
||||
<ButtonText>Se connecter</ButtonText>
|
||||
<ButtonIcon as={ArrowRightIcon} />
|
||||
<PasswordTextInput
|
||||
label="Mot de passe"
|
||||
onChangeText={setPassword}
|
||||
value={password}
|
||||
/>
|
||||
</View>
|
||||
<FormError isVisible={!isFormValid}>{error}</FormError>
|
||||
<Button onPress={onSubmit} afterIcon="arrowright">
|
||||
Se connecter
|
||||
</Button>
|
||||
</VStack>
|
||||
</FormControl>
|
||||
<Link href={"/sign-in"} asChild>
|
||||
<Button title="Se connecter"/>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -1,31 +0,0 @@
|
||||
import React from "react";
|
||||
import { LockIcon, EyeIcon, EyeOffIcon } from "../ui/icon";
|
||||
import { Input, InputIcon, InputField, InputSlot } from "../ui/input";
|
||||
import { VariantProps } from "@gluestack-ui/nativewind-utils";
|
||||
|
||||
type props = React.ComponentProps<typeof Input> &
|
||||
VariantProps<typeof InputField>;
|
||||
|
||||
export default function PasswordField({ value, onChangeText }: props) {
|
||||
const [showPassword, setShowPassword] = React.useState(false);
|
||||
const handleState = () => {
|
||||
setShowPassword((showState) => {
|
||||
return !showState;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Input variant="outline" size="xl">
|
||||
<InputIcon color="black" as={LockIcon} />
|
||||
<InputField
|
||||
value={value}
|
||||
onChangeText={onChangeText}
|
||||
type={showPassword ? "text" : "password"}
|
||||
placeholder="⋆⋆⋆⋆⋆⋆⋆⋆⋆⋆⋆⋆"
|
||||
/>
|
||||
<InputSlot className="pr-3" onPress={handleState}>
|
||||
<InputIcon as={showPassword ? EyeIcon : EyeOffIcon} />
|
||||
</InputSlot>
|
||||
</Input>
|
||||
);
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
import React, { useState } from "react";
|
||||
import FormInput, { FormInputProps } from "./FormInput";
|
||||
|
||||
export default React.forwardRef<any, FormInputProps>(
|
||||
(props, ref): React.ReactElement => {
|
||||
const { onBlur, onChangeText, value, label, ...rest } = props;
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
const toggleShowPassword = () => {
|
||||
setShowPassword(!showPassword);
|
||||
};
|
||||
|
||||
return (
|
||||
<FormInput
|
||||
label={label}
|
||||
beforeIcon="lock"
|
||||
afterIcon={showPassword ? "eye" : "eyeo"}
|
||||
placeholder="⋆⋆⋆⋆⋆⋆⋆⋆⋆⋆"
|
||||
onBlur={onBlur}
|
||||
onChangeText={onChangeText}
|
||||
value={value}
|
||||
onPress={toggleShowPassword}
|
||||
secureTextEntry={!showPassword}
|
||||
{...ref}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
@ -1,125 +1,82 @@
|
||||
import { Button, ButtonText, ButtonIcon } from "../ui/Button";
|
||||
import {
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
FormControlLabelText,
|
||||
} from "../ui/form-control";
|
||||
import { MailIcon, ArrowRightIcon } from "../ui/icon";
|
||||
import { Input, InputIcon, InputField } from "../ui/input";
|
||||
import { VStack } from "../ui/vstack";
|
||||
import { View, ViewProps } from "react-native";
|
||||
import TextInput from "./FormInput";
|
||||
import Button from "../ui/Button";
|
||||
import React from "react";
|
||||
import PasswordTextInput from "./SecretTextInput";
|
||||
import { isEmail } from "validator";
|
||||
import { EMPTY_FIELD, INVALID_EMAIL, NOT_MATCHING_PASSWORD } from "../Errors";
|
||||
import FormError from "./FormError";
|
||||
import PasswordField from "./PasswordField";
|
||||
|
||||
export default function SigninForm() {
|
||||
const REQUIRED = "Au moins un des champs requis est vide !";
|
||||
const INVALID_EMAIL = "Adresse mail invalide !";
|
||||
// TODO Définir ce qu'est un mdp valide
|
||||
const INVALID_PASSWORD = "Mot de passe invalide !";
|
||||
const NOT_MATCHING_PASSWORD = "Les mots de passe ne correspondent pas !";
|
||||
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
export default React.forwardRef<any, ViewProps>(
|
||||
(props, ref): React.ReactElement => {
|
||||
const { ...rest } = props;
|
||||
const [email, setEmail] = React.useState("");
|
||||
const [password, setPassword] = React.useState("");
|
||||
const [confirmPassword, setConfirmPassword] = React.useState("");
|
||||
const [error, setError] = React.useState("");
|
||||
const [isFormValid, setIsFormValid] = React.useState(true);
|
||||
|
||||
const [emailValue, setEmailValue] = React.useState("");
|
||||
const [isEmailInvalid, setIsEmailInvalid] = React.useState(false);
|
||||
const [passwordValue, setPasswordValue] = React.useState("");
|
||||
const [isPasswordInvalid, setIsPasswordInvalid] = React.useState(false);
|
||||
const [passwordConfirmValue, setPasswordConfirmValue] = React.useState("");
|
||||
const [isPasswordConfirmInvalid, setIsPasswordConfirmInvalid] =
|
||||
React.useState(false);
|
||||
const [isFormInvalid, setIsFormInvalid] = React.useState(false);
|
||||
const [formError, setFormError] = React.useState("");
|
||||
const validateForm = () => {
|
||||
setError("");
|
||||
setIsFormValid(true);
|
||||
};
|
||||
|
||||
function validateForm() {
|
||||
setFormError("");
|
||||
setIsFormInvalid(false);
|
||||
}
|
||||
|
||||
function invalidateForm(error: string) {
|
||||
setFormError(error);
|
||||
setIsFormInvalid(true);
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
//check for valid email block
|
||||
if (emailValue != "") {
|
||||
if (emailRegex.test(emailValue)) {
|
||||
setIsEmailInvalid(false);
|
||||
} else {
|
||||
setIsEmailInvalid(true);
|
||||
invalidateForm(INVALID_EMAIL);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
setIsEmailInvalid(true);
|
||||
invalidateForm(REQUIRED);
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO : check for valid password block
|
||||
if (passwordValue != "") {
|
||||
setIsPasswordInvalid(false);
|
||||
} else {
|
||||
setIsPasswordInvalid(true);
|
||||
invalidateForm(REQUIRED);
|
||||
return;
|
||||
}
|
||||
const invalidateForm = (error: string) => {
|
||||
setError(error);
|
||||
setIsFormValid(false);
|
||||
};
|
||||
|
||||
//check for valid password confirmation
|
||||
if (passwordConfirmValue != "") {
|
||||
if (passwordConfirmValue == passwordValue) {
|
||||
setIsPasswordConfirmInvalid(false);
|
||||
validateForm();
|
||||
const onSubmit = () => {
|
||||
if (email != "") {
|
||||
if (isEmail(email)) {
|
||||
if (password != "") {
|
||||
if (confirmPassword != "") {
|
||||
if (confirmPassword == password) {
|
||||
validateForm();
|
||||
console.log("tmp");
|
||||
} else {
|
||||
invalidateForm(NOT_MATCHING_PASSWORD);
|
||||
}
|
||||
} else {
|
||||
invalidateForm(EMPTY_FIELD);
|
||||
}
|
||||
} else {
|
||||
invalidateForm(EMPTY_FIELD);
|
||||
}
|
||||
} else {
|
||||
invalidateForm(INVALID_EMAIL);
|
||||
}
|
||||
} else {
|
||||
setIsPasswordConfirmInvalid(true);
|
||||
invalidateForm(NOT_MATCHING_PASSWORD);
|
||||
return;
|
||||
invalidateForm(EMPTY_FIELD);
|
||||
}
|
||||
} else {
|
||||
setIsPasswordConfirmInvalid(true);
|
||||
invalidateForm(REQUIRED);
|
||||
return;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<FormControl className="gap-4" isInvalid={isFormInvalid}>
|
||||
<FormControl isInvalid={isEmailInvalid}>
|
||||
<FormControlLabel>
|
||||
<FormControlLabelText bold={true}>Adresse mail</FormControlLabelText>
|
||||
</FormControlLabel>
|
||||
<Input variant="outline" size="xl">
|
||||
<InputIcon color="black" as={MailIcon} />
|
||||
<InputField
|
||||
value={emailValue}
|
||||
onChangeText={setEmailValue}
|
||||
placeholder="Test@optifit.com"
|
||||
return (
|
||||
<View className="gap-4" {...ref} {...rest}>
|
||||
<View className="gap-4">
|
||||
<TextInput
|
||||
beforeIcon="mail"
|
||||
placeholder="Test@Optifit.com"
|
||||
onChangeText={setEmail}
|
||||
value={email}
|
||||
label={"Adresse mail"}
|
||||
/>
|
||||
<PasswordTextInput
|
||||
onChangeText={setPassword}
|
||||
value={password}
|
||||
label={"Mot de passe"}
|
||||
/>
|
||||
</Input>
|
||||
</FormControl>
|
||||
<FormControl isInvalid={isPasswordInvalid}>
|
||||
<FormControlLabel>
|
||||
<FormControlLabelText bold={true}>Mot de passe</FormControlLabelText>
|
||||
</FormControlLabel>
|
||||
<PasswordField value={passwordValue} onChangeText={setPasswordValue} />
|
||||
</FormControl>
|
||||
<FormControl isInvalid={isPasswordConfirmInvalid}>
|
||||
<FormControlLabel>
|
||||
<FormControlLabelText bold={true}>
|
||||
Confirmation du mot de passe
|
||||
</FormControlLabelText>
|
||||
</FormControlLabel>
|
||||
<PasswordField
|
||||
value={passwordConfirmValue}
|
||||
onChangeText={setPasswordConfirmValue}
|
||||
/>
|
||||
</FormControl>
|
||||
<VStack>
|
||||
<FormError text={formError} />
|
||||
<Button size="xl" onPress={handleSubmit}>
|
||||
<ButtonText>S'inscrire</ButtonText>
|
||||
<ButtonIcon as={ArrowRightIcon} />
|
||||
<PasswordTextInput
|
||||
onChangeText={setConfirmPassword}
|
||||
value={confirmPassword}
|
||||
label={"Confirmation du mot de passe"}
|
||||
/>
|
||||
</View>
|
||||
<FormError isVisible={!isFormValid}>{error}</FormError>
|
||||
<Button onPress={onSubmit} afterIcon="arrowright">
|
||||
S'inscrire
|
||||
</Button>
|
||||
</VStack>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -1,17 +1,106 @@
|
||||
import React from "react";
|
||||
import { TouchableOpacity, View } from "react-native";
|
||||
import { TouchableOpacity, TouchableOpacityProps, View } from "react-native";
|
||||
import CustomText from "./Text";
|
||||
import { AntDesign } from "@expo/vector-icons";
|
||||
import { AntDesignIconNames } from "../Icons";
|
||||
import { Size } from "../Constants";
|
||||
|
||||
type props = { title: string; size: string };
|
||||
export type ButtonStyle = "default" | "outline" | "secondary";
|
||||
|
||||
const Button = ({ title, size }: props) => (
|
||||
<View className="bg-black rounded-3xl">
|
||||
<TouchableOpacity className="p-4">
|
||||
<CustomText center={true} color="white" size={size}>
|
||||
{title}
|
||||
</CustomText>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
//@ts-ignore
|
||||
interface Props extends TouchableOpacityProps {
|
||||
size?: Size;
|
||||
style?: ButtonStyle;
|
||||
insideClassName?: string;
|
||||
beforeIcon?: AntDesignIconNames;
|
||||
afterIcon?: AntDesignIconNames;
|
||||
}
|
||||
|
||||
export default React.forwardRef<any, Props>(
|
||||
(props, ref): React.ReactElement => {
|
||||
const {
|
||||
size,
|
||||
style,
|
||||
beforeIcon,
|
||||
afterIcon,
|
||||
onPress,
|
||||
className,
|
||||
insideClassName,
|
||||
children,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const getButtonStyle = (): string => {
|
||||
switch (style ?? "default") {
|
||||
case "default":
|
||||
return (
|
||||
"justify-center items-center bg-black text-white rounded-3xl" +
|
||||
" " +
|
||||
className
|
||||
);
|
||||
case "outline":
|
||||
return (
|
||||
"justify-center items-center border-black text-black border-2 rounded-3xl" +
|
||||
" " +
|
||||
className
|
||||
);
|
||||
case "secondary":
|
||||
return (
|
||||
"justify-center items-center bg-gray-200 text-black rounded-3xl" +
|
||||
" " +
|
||||
className
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default Button;
|
||||
const getIconSize = (): number => {
|
||||
switch (size ?? "lg") {
|
||||
case "xs":
|
||||
return 24;
|
||||
case "md":
|
||||
return 24;
|
||||
case "lg":
|
||||
return 24;
|
||||
case "xl":
|
||||
return 24;
|
||||
case "2xl":
|
||||
return 30;
|
||||
case "3xl":
|
||||
return 36;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View className={getButtonStyle()} {...ref} {...rest}>
|
||||
<TouchableOpacity
|
||||
className={"flex-row justify-center items-center gap-2 p-4 w-full"}
|
||||
onPress={onPress}
|
||||
>
|
||||
{beforeIcon != null ? (
|
||||
<AntDesign
|
||||
name={beforeIcon}
|
||||
color={style == null || style == "default" ? "white" : "black"}
|
||||
size={getIconSize()}
|
||||
/>
|
||||
) : null}
|
||||
<CustomText
|
||||
position="center"
|
||||
size={size ?? "lg"}
|
||||
weight="bold"
|
||||
color={style == null || style == "default" ? "white" : "black"}
|
||||
>
|
||||
{children}
|
||||
</CustomText>
|
||||
{afterIcon != null ? (
|
||||
<AntDesign
|
||||
className="w-auto"
|
||||
name={afterIcon}
|
||||
size={getIconSize()}
|
||||
color={style == null || style == "default" ? "white" : "black"}
|
||||
/>
|
||||
) : null}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { PropsWithChildren } from "react";
|
||||
import { View } from "react-native";
|
||||
import { View, ViewProps } from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import React from "react";
|
||||
|
||||
type props = PropsWithChildren;
|
||||
|
||||
export default function Screen({ children }: props) {
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<View className={"h-full pl-2 pr-2"}>{children}</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
export default React.forwardRef<any, ViewProps>(
|
||||
(props, ref): React.ReactElement => {
|
||||
const { children, ...rest } = props;
|
||||
return (
|
||||
<SafeAreaView className={"h-full p-4"} {...ref} {...rest}>
|
||||
<View>{children}</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -1,27 +1,62 @@
|
||||
import { PropsWithChildren } from "react";
|
||||
import { Text } from "react-native";
|
||||
import React from "react";
|
||||
import { Text, TextProps } from "react-native";
|
||||
import {
|
||||
Color,
|
||||
Position,
|
||||
Size,
|
||||
toTextColor,
|
||||
toTextPosition,
|
||||
toTextSize,
|
||||
toTextWeight,
|
||||
Weight,
|
||||
} from "../Constants";
|
||||
|
||||
type props = PropsWithChildren & {
|
||||
center?: boolean;
|
||||
color?: string;
|
||||
size?: string;
|
||||
bold?: boolean;
|
||||
export interface ExtendedTextProps extends TextProps {
|
||||
position?: Position;
|
||||
color?: Color;
|
||||
size?: Size;
|
||||
weight?: Weight;
|
||||
isLink?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
const CustomText = ({ children, center, color, size, bold, isLink }: props) => {
|
||||
const className =
|
||||
"text-" +
|
||||
(size ?? "md") +
|
||||
" " +
|
||||
(center ? "text-center" : "") +
|
||||
" " +
|
||||
("text-" + (color ?? "black ")) +
|
||||
" " +
|
||||
(bold ? "font-bold" : "") +
|
||||
" " +
|
||||
(isLink ? "text-orange-500 underline" : "");
|
||||
return <Text className={className}>{children}</Text>;
|
||||
};
|
||||
export default React.forwardRef<any, ExtendedTextProps>(
|
||||
(props, ref): React.ReactElement => {
|
||||
const {
|
||||
position,
|
||||
color,
|
||||
size,
|
||||
weight,
|
||||
isLink,
|
||||
className,
|
||||
children,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
export default CustomText;
|
||||
const buildClassName = () => {
|
||||
const textSize = toTextSize(size ?? "lg");
|
||||
const textColor = toTextColor(color ?? "black");
|
||||
const textWeight = toTextWeight(weight ?? "normal");
|
||||
const textPosition = toTextPosition(position ?? "left");
|
||||
|
||||
return (
|
||||
textSize +
|
||||
" " +
|
||||
textPosition +
|
||||
" " +
|
||||
textColor +
|
||||
" " +
|
||||
textWeight +
|
||||
" " +
|
||||
(isLink ? "text-orange-500 underline" : "") +
|
||||
" " +
|
||||
className
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Text className={buildClassName()} {...ref} {...rest}>
|
||||
{children}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
@ -1,19 +0,0 @@
|
||||
import React from "react";
|
||||
import { View, ViewProps } from "react-native";
|
||||
|
||||
import type { VariantProps } from "@gluestack-ui/nativewind-utils";
|
||||
import { boxStyle } from "./styles";
|
||||
|
||||
type IBoxProps = ViewProps &
|
||||
VariantProps<typeof boxStyle> & { className?: string };
|
||||
|
||||
const Box = React.forwardRef<React.ElementRef<typeof View>, IBoxProps>(
|
||||
({ className, ...props }, ref) => {
|
||||
return (
|
||||
<View ref={ref} {...props} className={boxStyle({ class: className })} />
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Box.displayName = "Box";
|
||||
export { Box };
|
@ -1,18 +0,0 @@
|
||||
import React from 'react';
|
||||
import { boxStyle } from './styles';
|
||||
|
||||
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
||||
|
||||
type IBoxProps = React.ComponentPropsWithoutRef<'div'> &
|
||||
VariantProps<typeof boxStyle> & { className?: string };
|
||||
|
||||
const Box = React.forwardRef<HTMLDivElement, IBoxProps>(
|
||||
({ className, ...props }, ref) => {
|
||||
return (
|
||||
<div ref={ref} className={boxStyle({ class: className })} {...props} />
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Box.displayName = 'Box';
|
||||
export { Box };
|
@ -1,10 +0,0 @@
|
||||
import { tva } from '@gluestack-ui/nativewind-utils/tva';
|
||||
import { isWeb } from '@gluestack-ui/nativewind-utils/IsWeb';
|
||||
|
||||
const baseStyle = isWeb
|
||||
? 'flex flex-col relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none'
|
||||
: '';
|
||||
|
||||
export const boxStyle = tva({
|
||||
base: baseStyle,
|
||||
});
|
@ -1,432 +0,0 @@
|
||||
"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;
|
@ -1,23 +0,0 @@
|
||||
import React from 'react';
|
||||
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
||||
import { View, ViewProps } from 'react-native';
|
||||
import { cardStyle } from './styles';
|
||||
|
||||
type ICardProps = ViewProps &
|
||||
VariantProps<typeof cardStyle> & { className?: string };
|
||||
|
||||
const Card = React.forwardRef<React.ElementRef<typeof View>, ICardProps>(
|
||||
({ className, size = 'md', variant = 'elevated', ...props }, ref) => {
|
||||
return (
|
||||
<View
|
||||
className={cardStyle({ size, variant, class: className })}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Card.displayName = 'Card';
|
||||
|
||||
export { Card };
|
@ -1,22 +0,0 @@
|
||||
import React from 'react';
|
||||
import { cardStyle } from './styles';
|
||||
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
||||
|
||||
type ICardProps = React.ComponentPropsWithoutRef<'div'> &
|
||||
VariantProps<typeof cardStyle>;
|
||||
|
||||
const Card = React.forwardRef<HTMLDivElement, ICardProps>(
|
||||
({ className, size = 'md', variant = 'elevated', ...props }, ref) => {
|
||||
return (
|
||||
<div
|
||||
className={cardStyle({ size, variant, class: className })}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Card.displayName = 'Card';
|
||||
|
||||
export { Card };
|
@ -1,20 +0,0 @@
|
||||
import { tva } from '@gluestack-ui/nativewind-utils/tva';
|
||||
import { isWeb } from '@gluestack-ui/nativewind-utils/IsWeb';
|
||||
const baseStyle = isWeb ? 'flex flex-col relative z-0' : '';
|
||||
|
||||
export const cardStyle = tva({
|
||||
base: baseStyle,
|
||||
variants: {
|
||||
size: {
|
||||
sm: 'p-3 rounded',
|
||||
md: 'p-4 rounded-md',
|
||||
lg: 'p-6 rounded-xl',
|
||||
},
|
||||
variant: {
|
||||
elevated: 'bg-background-0',
|
||||
outline: 'border border-outline-200 ',
|
||||
ghost: 'rounded-none',
|
||||
filled: 'bg-background-50',
|
||||
},
|
||||
},
|
||||
});
|
@ -1,468 +0,0 @@
|
||||
'use client';
|
||||
import { Text, View } from 'react-native';
|
||||
import React from 'react';
|
||||
import { createFormControl } from '@gluestack-ui/form-control';
|
||||
import { tva } from '@gluestack-ui/nativewind-utils/tva';
|
||||
import {
|
||||
withStyleContext,
|
||||
useStyleContext,
|
||||
} from '@gluestack-ui/nativewind-utils/withStyleContext';
|
||||
import { cssInterop } from 'nativewind';
|
||||
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
||||
import { PrimitiveIcon, UIIcon } from '@gluestack-ui/icon';
|
||||
|
||||
const SCOPE = 'FORM_CONTROL';
|
||||
|
||||
const formControlStyle = tva({
|
||||
base: 'flex flex-col',
|
||||
variants: {
|
||||
size: {
|
||||
sm: '',
|
||||
md: '',
|
||||
lg: '',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const formControlErrorIconStyle = tva({
|
||||
base: 'text-error-700 fill-none',
|
||||
variants: {
|
||||
size: {
|
||||
'2xs': 'h-3 w-3',
|
||||
'xs': 'h-3.5 w-3.5',
|
||||
'sm': 'h-4 w-4',
|
||||
'md': 'h-[18px] w-[18px]',
|
||||
'lg': 'h-5 w-5',
|
||||
'xl': 'h-6 w-6',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const formControlErrorStyle = tva({
|
||||
base: 'flex flex-row justify-start items-center mt-1 gap-1',
|
||||
});
|
||||
|
||||
const formControlErrorTextStyle = tva({
|
||||
base: 'text-error-700',
|
||||
variants: {
|
||||
isTruncated: {
|
||||
true: 'web:truncate',
|
||||
},
|
||||
bold: {
|
||||
true: 'font-bold',
|
||||
},
|
||||
underline: {
|
||||
true: 'underline',
|
||||
},
|
||||
strikeThrough: {
|
||||
true: 'line-through',
|
||||
},
|
||||
size: {
|
||||
'2xs': 'text-2xs',
|
||||
'xs': 'text-xs',
|
||||
'sm': 'text-sm',
|
||||
'md': 'text-base',
|
||||
'lg': 'text-lg',
|
||||
'xl': 'text-xl',
|
||||
'2xl': 'text-2xl',
|
||||
'3xl': 'text-3xl',
|
||||
'4xl': 'text-4xl',
|
||||
'5xl': 'text-5xl',
|
||||
'6xl': 'text-6xl',
|
||||
},
|
||||
sub: {
|
||||
true: 'text-xs',
|
||||
},
|
||||
italic: {
|
||||
true: 'italic',
|
||||
},
|
||||
highlight: {
|
||||
true: 'bg-yellow-500',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const formControlHelperStyle = tva({
|
||||
base: 'flex flex-row justify-start items-center mt-1',
|
||||
});
|
||||
|
||||
const formControlHelperTextStyle = tva({
|
||||
base: 'text-typography-500',
|
||||
variants: {
|
||||
isTruncated: {
|
||||
true: 'web:truncate',
|
||||
},
|
||||
bold: {
|
||||
true: 'font-bold',
|
||||
},
|
||||
underline: {
|
||||
true: 'underline',
|
||||
},
|
||||
strikeThrough: {
|
||||
true: 'line-through',
|
||||
},
|
||||
size: {
|
||||
'2xs': 'text-2xs',
|
||||
'xs': 'text-xs',
|
||||
'sm': 'text-xs',
|
||||
'md': 'text-sm',
|
||||
'lg': 'text-base',
|
||||
'xl': 'text-xl',
|
||||
'2xl': 'text-2xl',
|
||||
'3xl': 'text-3xl',
|
||||
'4xl': 'text-4xl',
|
||||
'5xl': 'text-5xl',
|
||||
'6xl': 'text-6xl',
|
||||
},
|
||||
sub: {
|
||||
true: 'text-xs',
|
||||
},
|
||||
italic: {
|
||||
true: 'italic',
|
||||
},
|
||||
highlight: {
|
||||
true: 'bg-yellow-500',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const formControlLabelStyle = tva({
|
||||
base: 'flex flex-row justify-start items-center mb-1',
|
||||
});
|
||||
|
||||
const formControlLabelTextStyle = tva({
|
||||
base: 'font-medium text-typography-900',
|
||||
variants: {
|
||||
isTruncated: {
|
||||
true: 'web:truncate',
|
||||
},
|
||||
bold: {
|
||||
true: 'font-bold',
|
||||
},
|
||||
underline: {
|
||||
true: 'underline',
|
||||
},
|
||||
strikeThrough: {
|
||||
true: 'line-through',
|
||||
},
|
||||
size: {
|
||||
'2xs': 'text-2xs',
|
||||
'xs': 'text-xs',
|
||||
'sm': 'text-sm',
|
||||
'md': 'text-base',
|
||||
'lg': 'text-lg',
|
||||
'xl': 'text-xl',
|
||||
'2xl': 'text-2xl',
|
||||
'3xl': 'text-3xl',
|
||||
'4xl': 'text-4xl',
|
||||
'5xl': 'text-5xl',
|
||||
'6xl': 'text-6xl',
|
||||
},
|
||||
sub: {
|
||||
true: 'text-xs',
|
||||
},
|
||||
italic: {
|
||||
true: 'italic',
|
||||
},
|
||||
highlight: {
|
||||
true: 'bg-yellow-500',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const formControlLabelAstrickStyle = tva({
|
||||
base: 'font-medium text-typography-900',
|
||||
variants: {
|
||||
isTruncated: {
|
||||
true: 'web:truncate',
|
||||
},
|
||||
bold: {
|
||||
true: 'font-bold',
|
||||
},
|
||||
underline: {
|
||||
true: 'underline',
|
||||
},
|
||||
strikeThrough: {
|
||||
true: 'line-through',
|
||||
},
|
||||
size: {
|
||||
'2xs': 'text-2xs',
|
||||
'xs': 'text-xs',
|
||||
'sm': 'text-sm',
|
||||
'md': 'text-base',
|
||||
'lg': 'text-lg',
|
||||
'xl': 'text-xl',
|
||||
'2xl': 'text-2xl',
|
||||
'3xl': 'text-3xl',
|
||||
'4xl': 'text-4xl',
|
||||
'5xl': 'text-5xl',
|
||||
'6xl': 'text-6xl',
|
||||
},
|
||||
sub: {
|
||||
true: 'text-xs',
|
||||
},
|
||||
italic: {
|
||||
true: 'italic',
|
||||
},
|
||||
highlight: {
|
||||
true: 'bg-yellow-500',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
type IFormControlLabelAstrickProps = React.ComponentPropsWithoutRef<
|
||||
typeof Text
|
||||
> &
|
||||
VariantProps<typeof formControlLabelAstrickStyle>;
|
||||
|
||||
const FormControlLabelAstrick = React.forwardRef<
|
||||
React.ElementRef<typeof Text>,
|
||||
IFormControlLabelAstrickProps
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { size: parentSize } = useStyleContext(SCOPE);
|
||||
|
||||
return (
|
||||
<Text
|
||||
ref={ref}
|
||||
className={formControlLabelAstrickStyle({
|
||||
parentVariants: { size: parentSize },
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export const UIFormControl = createFormControl({
|
||||
Root: withStyleContext(View, SCOPE),
|
||||
Error: View,
|
||||
ErrorText: Text,
|
||||
ErrorIcon: UIIcon,
|
||||
Label: View,
|
||||
LabelText: Text,
|
||||
LabelAstrick: FormControlLabelAstrick,
|
||||
Helper: View,
|
||||
HelperText: Text,
|
||||
});
|
||||
|
||||
cssInterop(PrimitiveIcon, {
|
||||
className: {
|
||||
target: 'style',
|
||||
nativeStyleToProp: {
|
||||
height: true,
|
||||
width: true,
|
||||
fill: true,
|
||||
color: true,
|
||||
stroke: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
type IFormControlProps = React.ComponentProps<typeof UIFormControl> &
|
||||
VariantProps<typeof formControlStyle>;
|
||||
|
||||
const FormControl = React.forwardRef<
|
||||
React.ElementRef<typeof UIFormControl>,
|
||||
IFormControlProps
|
||||
>(({ className, size = 'md', ...props }, ref) => {
|
||||
return (
|
||||
<UIFormControl
|
||||
ref={ref}
|
||||
className={formControlStyle({ size, class: className })}
|
||||
{...props}
|
||||
context={{ size }}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
type IFormControlErrorProps = React.ComponentProps<typeof UIFormControl.Error> &
|
||||
VariantProps<typeof formControlErrorStyle>;
|
||||
|
||||
const FormControlError = React.forwardRef<
|
||||
React.ElementRef<typeof UIFormControl.Error>,
|
||||
IFormControlErrorProps
|
||||
>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<UIFormControl.Error
|
||||
ref={ref}
|
||||
className={formControlErrorStyle({ class: className })}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
type IFormControlErrorTextProps = React.ComponentProps<
|
||||
typeof UIFormControl.Error.Text
|
||||
> &
|
||||
VariantProps<typeof formControlErrorTextStyle>;
|
||||
|
||||
const FormControlErrorText = React.forwardRef<
|
||||
React.ElementRef<typeof UIFormControl.Error.Text>,
|
||||
IFormControlErrorTextProps
|
||||
>(({ className, size, ...props }, ref) => {
|
||||
const { size: parentSize } = useStyleContext(SCOPE);
|
||||
return (
|
||||
<UIFormControl.Error.Text
|
||||
className={formControlErrorTextStyle({
|
||||
parentVariants: { size: parentSize },
|
||||
size,
|
||||
class: className,
|
||||
})}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
type IFormControlErrorIconProps = React.ComponentProps<
|
||||
typeof UIFormControl.Error.Icon
|
||||
> &
|
||||
VariantProps<typeof formControlErrorIconStyle> & {
|
||||
height?: number;
|
||||
width?: number;
|
||||
};
|
||||
|
||||
const FormControlErrorIcon = React.forwardRef<
|
||||
React.ElementRef<typeof UIFormControl.Error.Icon>,
|
||||
IFormControlErrorIconProps
|
||||
>(({ className, size, ...props }, ref) => {
|
||||
const { size: parentSize } = useStyleContext(SCOPE);
|
||||
|
||||
if (typeof size === 'number') {
|
||||
return (
|
||||
<UIFormControl.Error.Icon
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={formControlErrorIconStyle({ class: className })}
|
||||
size={size}
|
||||
/>
|
||||
);
|
||||
} else if (
|
||||
(props.height !== undefined || props.width !== undefined) &&
|
||||
size === undefined
|
||||
) {
|
||||
return (
|
||||
<UIFormControl.Error.Icon
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={formControlErrorIconStyle({ class: className })}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<UIFormControl.Error.Icon
|
||||
className={formControlErrorIconStyle({
|
||||
parentVariants: { size: parentSize },
|
||||
size,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
type IFormControlLabelProps = React.ComponentProps<typeof UIFormControl.Label> &
|
||||
VariantProps<typeof formControlLabelStyle>;
|
||||
|
||||
const FormControlLabel = React.forwardRef<
|
||||
React.ElementRef<typeof UIFormControl.Label>,
|
||||
IFormControlLabelProps
|
||||
>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<UIFormControl.Label
|
||||
ref={ref}
|
||||
className={formControlLabelStyle({ class: className })}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
type IFormControlLabelTextProps = React.ComponentProps<
|
||||
typeof UIFormControl.Label.Text
|
||||
> &
|
||||
VariantProps<typeof formControlLabelTextStyle>;
|
||||
|
||||
const FormControlLabelText = React.forwardRef<
|
||||
React.ElementRef<typeof UIFormControl.Label.Text>,
|
||||
IFormControlLabelTextProps
|
||||
>(({ className, size, ...props }, ref) => {
|
||||
const { size: parentSize } = useStyleContext(SCOPE);
|
||||
|
||||
return (
|
||||
<UIFormControl.Label.Text
|
||||
className={formControlLabelTextStyle({
|
||||
parentVariants: { size: parentSize },
|
||||
size,
|
||||
class: className,
|
||||
})}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
type IFormControlHelperProps = React.ComponentProps<
|
||||
typeof UIFormControl.Helper
|
||||
> &
|
||||
VariantProps<typeof formControlHelperStyle>;
|
||||
|
||||
const FormControlHelper = React.forwardRef<
|
||||
React.ElementRef<typeof UIFormControl.Helper>,
|
||||
IFormControlHelperProps
|
||||
>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<UIFormControl.Helper
|
||||
ref={ref}
|
||||
className={formControlHelperStyle({
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
type IFormControlHelperTextProps = React.ComponentProps<
|
||||
typeof UIFormControl.Helper.Text
|
||||
> &
|
||||
VariantProps<typeof formControlHelperTextStyle>;
|
||||
|
||||
const FormControlHelperText = React.forwardRef<
|
||||
React.ElementRef<typeof UIFormControl.Helper.Text>,
|
||||
IFormControlHelperTextProps
|
||||
>(({ className, size, ...props }, ref) => {
|
||||
const { size: parentSize } = useStyleContext(SCOPE);
|
||||
|
||||
return (
|
||||
<UIFormControl.Helper.Text
|
||||
className={formControlHelperTextStyle({
|
||||
parentVariants: { size: parentSize },
|
||||
size,
|
||||
class: className,
|
||||
})}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
FormControl.displayName = 'FormControl';
|
||||
FormControlError.displayName = 'FormControlError';
|
||||
FormControlErrorText.displayName = 'FormControlErrorText';
|
||||
FormControlErrorIcon.displayName = 'FormControlErrorIcon';
|
||||
FormControlLabel.displayName = 'FormControlLabel';
|
||||
FormControlLabelText.displayName = 'FormControlLabelText';
|
||||
FormControlLabelAstrick.displayName = 'FormControlLabelAstrick';
|
||||
FormControlHelper.displayName = 'FormControlHelper';
|
||||
FormControlHelperText.displayName = 'FormControlHelperText';
|
||||
|
||||
export {
|
||||
FormControl,
|
||||
FormControlError,
|
||||
FormControlErrorText,
|
||||
FormControlErrorIcon,
|
||||
FormControlLabel,
|
||||
FormControlLabelText,
|
||||
FormControlLabelAstrick,
|
||||
FormControlHelper,
|
||||
FormControlHelperText,
|
||||
};
|
@ -1,309 +0,0 @@
|
||||
"use client";
|
||||
import { vars } from "nativewind";
|
||||
|
||||
export const config = {
|
||||
light: vars({
|
||||
"--color-primary-0": "179 179 179",
|
||||
"--color-primary-50": "153 153 153",
|
||||
"--color-primary-100": "128 128 128",
|
||||
"--color-primary-200": "115 115 115",
|
||||
"--color-primary-300": "102 102 102",
|
||||
"--color-primary-400": "82 82 82",
|
||||
"--color-primary-500": "51 51 51",
|
||||
"--color-primary-600": "41 41 41",
|
||||
"--color-primary-700": "31 31 31",
|
||||
"--color-primary-800": "13 13 13",
|
||||
"--color-primary-900": "10 10 10",
|
||||
"--color-primary-950": "8 8 8",
|
||||
|
||||
/* Secondary */
|
||||
"--color-secondary-0": "253 253 253",
|
||||
"--color-secondary-50": "251 251 251",
|
||||
"--color-secondary-100": "246 246 246",
|
||||
"--color-secondary-200": "242 242 242",
|
||||
"--color-secondary-300": "237 237 237",
|
||||
"--color-secondary-400": "230 230 231",
|
||||
"--color-secondary-500": "217 217 219",
|
||||
"--color-secondary-600": "198 199 199",
|
||||
"--color-secondary-700": "189 189 189",
|
||||
"--color-secondary-800": "177 177 177",
|
||||
"--color-secondary-900": "165 164 164",
|
||||
"--color-secondary-950": "157 157 157",
|
||||
|
||||
/* Tertiary */
|
||||
"--color-tertiary-0": "255 250 245",
|
||||
"--color-tertiary-50": "255 242 229",
|
||||
"--color-tertiary-100": "255 233 213",
|
||||
"--color-tertiary-200": "254 209 170",
|
||||
"--color-tertiary-300": "253 180 116",
|
||||
"--color-tertiary-400": "251 157 75",
|
||||
"--color-tertiary-500": "231 129 40",
|
||||
"--color-tertiary-600": "215 117 31",
|
||||
"--color-tertiary-700": "180 98 26",
|
||||
"--color-tertiary-800": "130 73 23",
|
||||
"--color-tertiary-900": "108 61 19",
|
||||
"--color-tertiary-950": "84 49 18",
|
||||
|
||||
/* Error */
|
||||
"--color-error-0": "254 233 233",
|
||||
"--color-error-50": "254 226 226",
|
||||
"--color-error-100": "254 202 202",
|
||||
"--color-error-200": "252 165 165",
|
||||
"--color-error-300": "248 113 113",
|
||||
"--color-error-400": "239 68 68",
|
||||
"--color-error-500": "230 53 53",
|
||||
"--color-error-600": "220 38 38",
|
||||
"--color-error-700": "185 28 28",
|
||||
"--color-error-800": "153 27 27",
|
||||
"--color-error-900": "127 29 29",
|
||||
"--color-error-950": "83 19 19",
|
||||
|
||||
/* Success */
|
||||
"--color-success-0": "228 255 244",
|
||||
"--color-success-50": "202 255 232",
|
||||
"--color-success-100": "162 241 192",
|
||||
"--color-success-200": "132 211 162",
|
||||
"--color-success-300": "102 181 132",
|
||||
"--color-success-400": "72 151 102",
|
||||
"--color-success-500": "52 131 82",
|
||||
"--color-success-600": "42 121 72",
|
||||
"--color-success-700": "32 111 62",
|
||||
"--color-success-800": "22 101 52",
|
||||
"--color-success-900": "20 83 45",
|
||||
"--color-success-950": "27 50 36",
|
||||
|
||||
/* Warning */
|
||||
"--color-warning-0": "255 249 245",
|
||||
"--color-warning-50": "255 244 236",
|
||||
"--color-warning-100": "255 231 213",
|
||||
"--color-warning-200": "254 205 170",
|
||||
"--color-warning-300": "253 173 116",
|
||||
"--color-warning-400": "251 149 75",
|
||||
"--color-warning-500": "231 120 40",
|
||||
"--color-warning-600": "215 108 31",
|
||||
"--color-warning-700": "180 90 26",
|
||||
"--color-warning-800": "130 68 23",
|
||||
"--color-warning-900": "108 56 19",
|
||||
"--color-warning-950": "84 45 18",
|
||||
|
||||
/* Info */
|
||||
"--color-info-0": "236 248 254",
|
||||
"--color-info-50": "199 235 252",
|
||||
"--color-info-100": "162 221 250",
|
||||
"--color-info-200": "124 207 248",
|
||||
"--color-info-300": "87 194 246",
|
||||
"--color-info-400": "50 180 244",
|
||||
"--color-info-500": "13 166 242",
|
||||
"--color-info-600": "11 141 205",
|
||||
"--color-info-700": "9 115 168",
|
||||
"--color-info-800": "7 90 131",
|
||||
"--color-info-900": "5 64 93",
|
||||
"--color-info-950": "3 38 56",
|
||||
|
||||
/* Typography */
|
||||
"--color-typography-0": "254 254 255",
|
||||
"--color-typography-50": "245 245 245",
|
||||
"--color-typography-100": "229 229 229",
|
||||
"--color-typography-200": "219 219 220",
|
||||
"--color-typography-300": "212 212 212",
|
||||
"--color-typography-400": "163 163 163",
|
||||
"--color-typography-500": "140 140 140",
|
||||
"--color-typography-600": "115 115 115",
|
||||
"--color-typography-700": "82 82 82",
|
||||
"--color-typography-800": "64 64 64",
|
||||
"--color-typography-900": "38 38 39",
|
||||
"--color-typography-950": "23 23 23",
|
||||
|
||||
/* Outline */
|
||||
"--color-outline-0": "253 254 254",
|
||||
"--color-outline-50": "243 243 243",
|
||||
"--color-outline-100": "230 230 230",
|
||||
"--color-outline-200": "221 220 219",
|
||||
"--color-outline-300": "211 211 211",
|
||||
"--color-outline-400": "165 163 163",
|
||||
"--color-outline-500": "140 141 141",
|
||||
"--color-outline-600": "115 116 116",
|
||||
"--color-outline-700": "83 82 82",
|
||||
"--color-outline-800": "65 65 65",
|
||||
"--color-outline-900": "39 38 36",
|
||||
"--color-outline-950": "26 23 23",
|
||||
|
||||
/* Background */
|
||||
"--color-background-0": "255 255 255",
|
||||
"--color-background-50": "246 246 246",
|
||||
"--color-background-100": "242 241 241",
|
||||
"--color-background-200": "220 219 219",
|
||||
"--color-background-300": "213 212 212",
|
||||
"--color-background-400": "162 163 163",
|
||||
"--color-background-500": "142 142 142",
|
||||
"--color-background-600": "116 116 116",
|
||||
"--color-background-700": "83 82 82",
|
||||
"--color-background-800": "65 64 64",
|
||||
"--color-background-900": "39 38 37",
|
||||
"--color-background-950": "18 18 18",
|
||||
|
||||
/* Background Special */
|
||||
"--color-background-error": "254 241 241",
|
||||
"--color-background-warning": "255 243 234",
|
||||
"--color-background-success": "237 252 242",
|
||||
"--color-background-muted": "247 248 247",
|
||||
"--color-background-info": "235 248 254",
|
||||
|
||||
/* Focus Ring Indicator */
|
||||
"--color-indicator-primary": "55 55 55",
|
||||
"--color-indicator-info": "83 153 236",
|
||||
"--color-indicator-error": "185 28 28",
|
||||
}),
|
||||
dark: vars({
|
||||
"--color-primary-0": "166 166 166",
|
||||
"--color-primary-50": "175 175 175",
|
||||
"--color-primary-100": "186 186 186",
|
||||
"--color-primary-200": "197 197 197",
|
||||
"--color-primary-300": "212 212 212",
|
||||
"--color-primary-400": "221 221 221",
|
||||
"--color-primary-500": "230 230 230",
|
||||
"--color-primary-600": "240 240 240",
|
||||
"--color-primary-700": "250 250 250",
|
||||
"--color-primary-800": "253 253 253",
|
||||
"--color-primary-900": "254 249 249",
|
||||
"--color-primary-950": "253 252 252",
|
||||
|
||||
/* Secondary */
|
||||
"--color-secondary-0": "20 20 20",
|
||||
"--color-secondary-50": "23 23 23",
|
||||
"--color-secondary-100": "31 31 31",
|
||||
"--color-secondary-200": "39 39 39",
|
||||
"--color-secondary-300": "44 44 44",
|
||||
"--color-secondary-400": "56 57 57",
|
||||
"--color-secondary-500": "63 64 64",
|
||||
"--color-secondary-600": "86 86 86",
|
||||
"--color-secondary-700": "110 110 110",
|
||||
"--color-secondary-800": "135 135 135",
|
||||
"--color-secondary-900": "150 150 150",
|
||||
"--color-secondary-950": "164 164 164",
|
||||
|
||||
/* Tertiary */
|
||||
"--color-tertiary-0": "84 49 18",
|
||||
"--color-tertiary-50": "108 61 19",
|
||||
"--color-tertiary-100": "130 73 23",
|
||||
"--color-tertiary-200": "180 98 26",
|
||||
"--color-tertiary-300": "215 117 31",
|
||||
"--color-tertiary-400": "231 129 40",
|
||||
"--color-tertiary-500": "251 157 75",
|
||||
"--color-tertiary-600": "253 180 116",
|
||||
"--color-tertiary-700": "254 209 170",
|
||||
"--color-tertiary-800": "255 233 213",
|
||||
"--color-tertiary-900": "255 242 229",
|
||||
"--color-tertiary-950": "255 250 245",
|
||||
|
||||
/* Error */
|
||||
"--color-error-0": "83 19 19",
|
||||
"--color-error-50": "127 29 29",
|
||||
"--color-error-100": "153 27 27",
|
||||
"--color-error-200": "185 28 28",
|
||||
"--color-error-300": "220 38 38",
|
||||
"--color-error-400": "230 53 53",
|
||||
"--color-error-500": "239 68 68",
|
||||
"--color-error-600": "249 97 96",
|
||||
"--color-error-700": "229 91 90",
|
||||
"--color-error-800": "254 202 202",
|
||||
"--color-error-900": "254 226 226",
|
||||
"--color-error-950": "254 233 233",
|
||||
|
||||
/* Success */
|
||||
"--color-success-0": "27 50 36",
|
||||
"--color-success-50": "20 83 45",
|
||||
"--color-success-100": "22 101 52",
|
||||
"--color-success-200": "32 111 62",
|
||||
"--color-success-300": "42 121 72",
|
||||
"--color-success-400": "52 131 82",
|
||||
"--color-success-500": "72 151 102",
|
||||
"--color-success-600": "102 181 132",
|
||||
"--color-success-700": "132 211 162",
|
||||
"--color-success-800": "162 241 192",
|
||||
"--color-success-900": "202 255 232",
|
||||
"--color-success-950": "228 255 244",
|
||||
|
||||
/* Warning */
|
||||
"--color-warning-0": "84 45 18",
|
||||
"--color-warning-50": "108 56 19",
|
||||
"--color-warning-100": "130 68 23",
|
||||
"--color-warning-200": "180 90 26",
|
||||
"--color-warning-300": "215 108 31",
|
||||
"--color-warning-400": "231 120 40",
|
||||
"--color-warning-500": "251 149 75",
|
||||
"--color-warning-600": "253 173 116",
|
||||
"--color-warning-700": "254 205 170",
|
||||
"--color-warning-800": "255 231 213",
|
||||
"--color-warning-900": "255 244 237",
|
||||
"--color-warning-950": "255 249 245",
|
||||
|
||||
/* Info */
|
||||
"--color-info-0": "3 38 56",
|
||||
"--color-info-50": "5 64 93",
|
||||
"--color-info-100": "7 90 131",
|
||||
"--color-info-200": "9 115 168",
|
||||
"--color-info-300": "11 141 205",
|
||||
"--color-info-400": "13 166 242",
|
||||
"--color-info-500": "50 180 244",
|
||||
"--color-info-600": "87 194 246",
|
||||
"--color-info-700": "124 207 248",
|
||||
"--color-info-800": "162 221 250",
|
||||
"--color-info-900": "199 235 252",
|
||||
"--color-info-950": "236 248 254",
|
||||
|
||||
/* Typography */
|
||||
"--color-typography-0": "23 23 23",
|
||||
"--color-typography-50": "38 38 39",
|
||||
"--color-typography-100": "64 64 64",
|
||||
"--color-typography-200": "82 82 82",
|
||||
"--color-typography-300": "115 115 115",
|
||||
"--color-typography-400": "140 140 140",
|
||||
"--color-typography-500": "163 163 163",
|
||||
"--color-typography-600": "212 212 212",
|
||||
"--color-typography-700": "219 219 220",
|
||||
"--color-typography-800": "229 229 229",
|
||||
"--color-typography-900": "245 245 245",
|
||||
"--color-typography-950": "254 254 255",
|
||||
|
||||
/* Outline */
|
||||
"--color-outline-0": "26 23 23",
|
||||
"--color-outline-50": "39 38 36",
|
||||
"--color-outline-100": "65 65 65",
|
||||
"--color-outline-200": "83 82 82",
|
||||
"--color-outline-300": "115 116 116",
|
||||
"--color-outline-400": "140 141 141",
|
||||
"--color-outline-500": "165 163 163",
|
||||
"--color-outline-600": "211 211 211",
|
||||
"--color-outline-700": "221 220 219",
|
||||
"--color-outline-800": "230 230 230",
|
||||
"--color-outline-900": "243 243 243",
|
||||
"--color-outline-950": "253 254 254",
|
||||
|
||||
/* Background */
|
||||
"--color-background-0": "18 18 18",
|
||||
"--color-background-50": "39 38 37",
|
||||
"--color-background-100": "65 64 64",
|
||||
"--color-background-200": "83 82 82",
|
||||
"--color-background-300": "116 116 116",
|
||||
"--color-background-400": "142 142 142",
|
||||
"--color-background-500": "162 163 163",
|
||||
"--color-background-600": "213 212 212",
|
||||
"--color-background-700": "229 228 228",
|
||||
"--color-background-800": "242 241 241",
|
||||
"--color-background-900": "246 246 246",
|
||||
"--color-background-950": "255 255 255",
|
||||
|
||||
/* Background Special */
|
||||
"--color-background-error": "66 43 43",
|
||||
"--color-background-warning": "65 47 35",
|
||||
"--color-background-success": "28 43 33",
|
||||
"--color-background-muted": "51 51 51",
|
||||
"--color-background-info": "26 40 46",
|
||||
|
||||
/* Focus Ring Indicator */
|
||||
"--color-indicator-primary": "247 247 247",
|
||||
"--color-indicator-info": "161 199 245",
|
||||
"--color-indicator-error": "232 70 69",
|
||||
}),
|
||||
};
|
@ -1,48 +0,0 @@
|
||||
import React from "react";
|
||||
import { config } from "./config";
|
||||
import { ColorSchemeName, useColorScheme, View, ViewProps } from "react-native";
|
||||
import { OverlayProvider } from "@gluestack-ui/overlay";
|
||||
import { ToastProvider } from "@gluestack-ui/toast";
|
||||
import { colorScheme as colorSchemeNW } from "nativewind";
|
||||
|
||||
type ModeType = "light" | "dark" | "system";
|
||||
|
||||
const getColorSchemeName = (
|
||||
colorScheme: ColorSchemeName,
|
||||
mode: ModeType
|
||||
): "light" | "dark" => {
|
||||
if (mode === "system") {
|
||||
return colorScheme ?? "light";
|
||||
}
|
||||
return mode;
|
||||
};
|
||||
|
||||
export function GluestackUIProvider({
|
||||
mode = "light",
|
||||
...props
|
||||
}: {
|
||||
mode?: "light" | "dark" | "system";
|
||||
children?: React.ReactNode;
|
||||
style?: ViewProps["style"];
|
||||
}) {
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
const colorSchemeName = getColorSchemeName(colorScheme, mode);
|
||||
|
||||
colorSchemeNW.set(mode);
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
config[colorSchemeName],
|
||||
// eslint-disable-next-line react-native/no-inline-styles
|
||||
{ flex: 1, height: "100%", width: "100%" },
|
||||
props.style,
|
||||
]}
|
||||
>
|
||||
<OverlayProvider>
|
||||
<ToastProvider>{props.children}</ToastProvider>
|
||||
</OverlayProvider>
|
||||
</View>
|
||||
);
|
||||
}
|
@ -1,219 +0,0 @@
|
||||
import React, { forwardRef, memo } from 'react';
|
||||
import { H1, H2, H3, H4, H5, H6 } from '@expo/html-elements';
|
||||
import { headingStyle } from './styles';
|
||||
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
||||
import { cssInterop } from 'nativewind';
|
||||
|
||||
type IHeadingProps = VariantProps<typeof headingStyle> &
|
||||
React.ComponentPropsWithoutRef<typeof H1> & {
|
||||
as?: React.ElementType;
|
||||
};
|
||||
|
||||
cssInterop(H1, { className: 'style' });
|
||||
cssInterop(H2, { className: 'style' });
|
||||
cssInterop(H3, { className: 'style' });
|
||||
cssInterop(H4, { className: 'style' });
|
||||
cssInterop(H5, { className: 'style' });
|
||||
cssInterop(H6, { className: 'style' });
|
||||
|
||||
const MappedHeading = memo(
|
||||
forwardRef<React.ElementRef<typeof H1>, IHeadingProps>(
|
||||
(
|
||||
{
|
||||
size,
|
||||
className,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
switch (size) {
|
||||
case '5xl':
|
||||
case '4xl':
|
||||
case '3xl':
|
||||
return (
|
||||
<H1
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
// @ts-expect-error
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
case '2xl':
|
||||
return (
|
||||
<H2
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
// @ts-expect-error
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
case 'xl':
|
||||
return (
|
||||
<H3
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
// @ts-expect-error
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
case 'lg':
|
||||
return (
|
||||
<H4
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
// @ts-expect-error
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
case 'md':
|
||||
return (
|
||||
<H5
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
// @ts-expect-error
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
case 'sm':
|
||||
case 'xs':
|
||||
return (
|
||||
<H6
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
// @ts-expect-error
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<H4
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
// @ts-expect-error
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
const Heading = memo(
|
||||
forwardRef<React.ElementRef<typeof H1>, IHeadingProps>(
|
||||
({ className, size = 'lg', as: AsComp, ...props }, ref) => {
|
||||
const {
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
} = props;
|
||||
|
||||
if (AsComp) {
|
||||
return (
|
||||
<AsComp
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<MappedHeading className={className} size={size} ref={ref} {...props} />
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
Heading.displayName = 'Heading';
|
||||
|
||||
export { Heading };
|
@ -1,203 +0,0 @@
|
||||
import React, { forwardRef, memo } from 'react';
|
||||
import { headingStyle } from './styles';
|
||||
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
||||
type IHeadingProps = VariantProps<typeof headingStyle> &
|
||||
React.ComponentPropsWithoutRef<'h1'> & {
|
||||
as?: React.ElementType;
|
||||
};
|
||||
|
||||
const MappedHeading = memo(
|
||||
forwardRef<HTMLHeadingElement, IHeadingProps>(
|
||||
(
|
||||
{
|
||||
size,
|
||||
className,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
switch (size) {
|
||||
case '5xl':
|
||||
case '4xl':
|
||||
case '3xl':
|
||||
return (
|
||||
<h1
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
case '2xl':
|
||||
return (
|
||||
<h2
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
case 'xl':
|
||||
return (
|
||||
<h3
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
case 'lg':
|
||||
return (
|
||||
<h4
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
case 'md':
|
||||
return (
|
||||
<h5
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
case 'sm':
|
||||
case 'xs':
|
||||
return (
|
||||
<h6
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<h4
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
const Heading = memo(
|
||||
forwardRef<HTMLHeadingElement, IHeadingProps>(
|
||||
({ className, size = 'lg', as: AsComp, ...props }, ref) => {
|
||||
const {
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
} = props;
|
||||
|
||||
if (AsComp) {
|
||||
return (
|
||||
<AsComp
|
||||
className={headingStyle({
|
||||
size,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<MappedHeading className={className} size={size} ref={ref} {...props} />
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
Heading.displayName = 'Heading';
|
||||
|
||||
export { Heading };
|
@ -1,43 +0,0 @@
|
||||
import { tva } from "@gluestack-ui/nativewind-utils/tva";
|
||||
import { isWeb } from "@gluestack-ui/nativewind-utils/IsWeb";
|
||||
const baseStyle = isWeb
|
||||
? "font-sans tracking-sm bg-transparent border-0 box-border display-inline list-none margin-0 padding-0 position-relative text-start no-underline whitespace-pre-wrap word-wrap-break-word"
|
||||
: "";
|
||||
|
||||
export const headingStyle = tva({
|
||||
base: `text-typography-900 font-bold font-heading tracking-sm my-0 ${baseStyle}`,
|
||||
variants: {
|
||||
isTruncated: {
|
||||
true: "truncate",
|
||||
},
|
||||
bold: {
|
||||
true: "font-bold",
|
||||
},
|
||||
underline: {
|
||||
true: "underline",
|
||||
},
|
||||
strikeThrough: {
|
||||
true: "line-through",
|
||||
},
|
||||
sub: {
|
||||
true: "text-xs",
|
||||
},
|
||||
italic: {
|
||||
true: "italic",
|
||||
},
|
||||
highlight: {
|
||||
true: "bg-yellow-500",
|
||||
},
|
||||
size: {
|
||||
"5xl": "text-6xl",
|
||||
"4xl": "text-5xl",
|
||||
"3xl": "text-4xl",
|
||||
"2xl": "text-3xl",
|
||||
xl: "text-2xl",
|
||||
lg: "text-xl",
|
||||
md: "text-lg",
|
||||
sm: "text-base",
|
||||
xs: "text-sm",
|
||||
},
|
||||
},
|
||||
});
|
@ -1,23 +0,0 @@
|
||||
import React from 'react';
|
||||
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
||||
import { View } from 'react-native';
|
||||
import type { ViewProps } from 'react-native';
|
||||
import { hstackStyle } from './styles';
|
||||
|
||||
type IHStackProps = ViewProps & VariantProps<typeof hstackStyle>;
|
||||
|
||||
const HStack = React.forwardRef<React.ElementRef<typeof View>, IHStackProps>(
|
||||
({ className, space, reversed, ...props }, ref) => {
|
||||
return (
|
||||
<View
|
||||
className={hstackStyle({ space, reversed, class: className })}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
HStack.displayName = 'HStack';
|
||||
|
||||
export { HStack };
|
@ -1,22 +0,0 @@
|
||||
import React from 'react';
|
||||
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
||||
import { hstackStyle } from './styles';
|
||||
|
||||
type IHStackProps = React.ComponentPropsWithoutRef<'div'> &
|
||||
VariantProps<typeof hstackStyle>;
|
||||
|
||||
const HStack = React.forwardRef<React.ElementRef<'div'>, IHStackProps>(
|
||||
({ className, space, reversed, ...props }, ref) => {
|
||||
return (
|
||||
<div
|
||||
className={hstackStyle({ space, reversed, class: className })}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
HStack.displayName = 'HStack';
|
||||
|
||||
export { HStack };
|
@ -1,25 +0,0 @@
|
||||
import { isWeb } from "@gluestack-ui/nativewind-utils/IsWeb";
|
||||
import { tva } from "@gluestack-ui/nativewind-utils/tva";
|
||||
|
||||
const baseStyle = isWeb
|
||||
? "flex relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none"
|
||||
: "";
|
||||
|
||||
export const hstackStyle = tva({
|
||||
base: `flex-row ${baseStyle}`,
|
||||
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",
|
||||
},
|
||||
reversed: {
|
||||
true: "flex-row-reverse",
|
||||
},
|
||||
},
|
||||
});
|
@ -1,214 +0,0 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { createInput } from "@gluestack-ui/input";
|
||||
import { View, Pressable, TextInput } from "react-native";
|
||||
import { tva } from "@gluestack-ui/nativewind-utils/tva";
|
||||
import {
|
||||
withStyleContext,
|
||||
useStyleContext,
|
||||
} from "@gluestack-ui/nativewind-utils/withStyleContext";
|
||||
import { cssInterop } from "nativewind";
|
||||
import type { VariantProps } from "@gluestack-ui/nativewind-utils";
|
||||
import { PrimitiveIcon, UIIcon } from "@gluestack-ui/icon";
|
||||
|
||||
const SCOPE = "INPUT";
|
||||
|
||||
const UIInput = createInput({
|
||||
Root: withStyleContext(View, SCOPE),
|
||||
Icon: UIIcon,
|
||||
Slot: Pressable,
|
||||
Input: TextInput,
|
||||
});
|
||||
|
||||
cssInterop(PrimitiveIcon, {
|
||||
className: {
|
||||
target: "style",
|
||||
nativeStyleToProp: {
|
||||
height: true,
|
||||
width: true,
|
||||
fill: true,
|
||||
color: "classNameColor",
|
||||
stroke: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const inputStyle = tva({
|
||||
base: "border-background-300 flex-row overflow-hidden content-center data-[hover=true]:border-outline-400 data-[focus=true]:border-orange-400 data-[focus=true]:hover:border-primary-700 data-[disabled=true]:opacity-40 data-[disabled=true]:hover:border-background-300 items-center",
|
||||
|
||||
variants: {
|
||||
size: {
|
||||
xl: "px-4 h-16",
|
||||
lg: "px-4 h-11",
|
||||
md: "px-4 h-10",
|
||||
sm: "px-4 h-9",
|
||||
},
|
||||
|
||||
variant: {
|
||||
underlined:
|
||||
"rounded-none border-b data-[invalid=true]:border-b-2 data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700",
|
||||
|
||||
outline:
|
||||
"rounded-3xl border data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700 data-[focus=true]:web:ring-1 data-[focus=true]:web:ring-inset data-[focus=true]:web:ring-indicator-primary data-[invalid=true]:web:ring-1 data-[invalid=true]:web:ring-inset data-[invalid=true]:web:ring-indicator-error data-[invalid=true]:data-[focus=true]:hover:web:ring-1 data-[invalid=true]:data-[focus=true]:hover:web:ring-inset data-[invalid=true]:data-[focus=true]:hover:web:ring-indicator-error data-[invalid=true]:data-[disabled=true]:hover:web:ring-1 data-[invalid=true]:data-[disabled=true]:hover:web:ring-inset data-[invalid=true]:data-[disabled=true]:hover:web:ring-indicator-error",
|
||||
|
||||
rounded:
|
||||
"rounded-full border data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700 data-[focus=true]:web:ring-1 data-[focus=true]:web:ring-inset data-[focus=true]:web:ring-indicator-primary data-[invalid=true]:web:ring-1 data-[invalid=true]:web:ring-inset data-[invalid=true]:web:ring-indicator-error data-[invalid=true]:data-[focus=true]:hover:web:ring-1 data-[invalid=true]:data-[focus=true]:hover:web:ring-inset data-[invalid=true]:data-[focus=true]:hover:web:ring-indicator-error data-[invalid=true]:data-[disabled=true]:hover:web:ring-1 data-[invalid=true]:data-[disabled=true]:hover:web:ring-inset data-[invalid=true]:data-[disabled=true]:hover:web:ring-indicator-error",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const inputIconStyle = tva({
|
||||
base: "justify-center items-center text-typography-400 fill-none",
|
||||
parentVariants: {
|
||||
size: {
|
||||
"2xs": "h-3 w-3",
|
||||
xs: "h-3.5 w-3.5",
|
||||
sm: "h-4 w-4",
|
||||
md: "h-[18px] w-[18px]",
|
||||
lg: "h-5 w-5",
|
||||
xl: "h-6 w-6",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const inputSlotStyle = tva({
|
||||
base: "justify-center items-center web:disabled:cursor-not-allowed",
|
||||
});
|
||||
|
||||
const inputFieldStyle = tva({
|
||||
base: "flex-1 text-typography-900 py-0 px-3 placeholder:text-typography-500 h-full ios:leading-[0px] web:cursor-text web:data-[disabled=true]:cursor-not-allowed",
|
||||
|
||||
parentVariants: {
|
||||
variant: {
|
||||
underlined: "web:outline-0 web:outline-none px-0",
|
||||
outline: "web:outline-0 web:outline-none",
|
||||
rounded: "web:outline-0 web:outline-none px-4",
|
||||
},
|
||||
|
||||
size: {
|
||||
"2xs": "text-2xs",
|
||||
xs: "text-xs",
|
||||
sm: "text-sm",
|
||||
md: "text-base",
|
||||
lg: "text-lg",
|
||||
xl: "text-xl",
|
||||
"2xl": "text-2xl",
|
||||
"3xl": "text-3xl",
|
||||
"4xl": "text-4xl",
|
||||
"5xl": "text-5xl",
|
||||
"6xl": "text-6xl",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
type IInputProps = React.ComponentProps<typeof UIInput> &
|
||||
VariantProps<typeof inputStyle> & { className?: string };
|
||||
const Input = React.forwardRef<React.ElementRef<typeof UIInput>, IInputProps>(
|
||||
({ className, variant = "outline", size = "md", ...props }, ref) => {
|
||||
return (
|
||||
<UIInput
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={inputStyle({ variant, size, class: className })}
|
||||
context={{ variant, size }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
type IInputIconProps = React.ComponentProps<typeof UIInput.Icon> &
|
||||
VariantProps<typeof inputIconStyle> & {
|
||||
className?: string;
|
||||
height?: number;
|
||||
width?: number;
|
||||
};
|
||||
|
||||
const InputIcon = React.forwardRef<
|
||||
React.ElementRef<typeof UIInput.Icon>,
|
||||
IInputIconProps
|
||||
>(({ className, size, ...props }, ref) => {
|
||||
const { size: parentSize } = useStyleContext(SCOPE);
|
||||
|
||||
if (typeof size === "number") {
|
||||
return (
|
||||
<UIInput.Icon
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={inputIconStyle({ class: className })}
|
||||
size={size}
|
||||
/>
|
||||
);
|
||||
} else if (
|
||||
(props.height !== undefined || props.width !== undefined) &&
|
||||
size === undefined
|
||||
) {
|
||||
return (
|
||||
<UIInput.Icon
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={inputIconStyle({ class: className })}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<UIInput.Icon
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={inputIconStyle({
|
||||
parentVariants: {
|
||||
size: parentSize,
|
||||
},
|
||||
class: className,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
type IInputSlotProps = React.ComponentProps<typeof UIInput.Slot> &
|
||||
VariantProps<typeof inputSlotStyle> & { className?: string };
|
||||
|
||||
const InputSlot = React.forwardRef<
|
||||
React.ElementRef<typeof UIInput.Slot>,
|
||||
IInputSlotProps
|
||||
>(({ className, ...props }, ref) => {
|
||||
return (
|
||||
<UIInput.Slot
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={inputSlotStyle({
|
||||
class: className,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
type IInputFieldProps = React.ComponentProps<typeof UIInput.Input> &
|
||||
VariantProps<typeof inputFieldStyle> & { className?: string };
|
||||
|
||||
const InputField = React.forwardRef<
|
||||
React.ElementRef<typeof UIInput.Input>,
|
||||
IInputFieldProps
|
||||
>(({ className, ...props }, ref) => {
|
||||
const { variant: parentVariant, size: parentSize } = useStyleContext(SCOPE);
|
||||
|
||||
return (
|
||||
<UIInput.Input
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={inputFieldStyle({
|
||||
parentVariants: {
|
||||
variant: parentVariant,
|
||||
size: parentSize,
|
||||
},
|
||||
class: className,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
Input.displayName = "Input";
|
||||
InputIcon.displayName = "InputIcon";
|
||||
InputSlot.displayName = "InputSlot";
|
||||
InputField.displayName = "InputField";
|
||||
|
||||
export { Input, InputField, InputIcon, InputSlot };
|
@ -1,102 +0,0 @@
|
||||
"use client";
|
||||
import { createLink } from "@gluestack-ui/link";
|
||||
import { Pressable } from "react-native";
|
||||
import { Text } from "react-native";
|
||||
|
||||
import { tva } from "@gluestack-ui/nativewind-utils/tva";
|
||||
import { withStyleContext } from "@gluestack-ui/nativewind-utils/withStyleContext";
|
||||
import { cssInterop } from "nativewind";
|
||||
import type { VariantProps } from "@gluestack-ui/nativewind-utils";
|
||||
|
||||
import React from "react";
|
||||
export const UILink = createLink({
|
||||
Root: withStyleContext(Pressable),
|
||||
Text: Text,
|
||||
});
|
||||
|
||||
cssInterop(UILink, { className: "style" });
|
||||
cssInterop(UILink.Text, { className: "style" });
|
||||
|
||||
const linkStyle = tva({
|
||||
base: "group/link web:outline-0 data-[disabled=true]:web:cursor-not-allowed data-[focus-visible=true]:web:ring-2 data-[focus-visible=true]:web:ring-indicator-primary data-[focus-visible=true]:web:outline-0 data-[disabled=true]:opacity-4 ",
|
||||
});
|
||||
|
||||
const linkTextStyle = tva({
|
||||
base: "underline text-orange-400 data-[hover=true]:text-orange-400 data-[hover=true]:no-underline data-[active=true]:text-orange-400 font-normal font-body web:font-sans web:tracking-sm web:my-0 web:bg-transparent web:border-0 web:box-border web:display-inline web:list-none web:margin-0 web:padding-0 web:position-relative web:text-start web:whitespace-pre-wrap web:word-wrap-break-word",
|
||||
|
||||
variants: {
|
||||
isTruncated: {
|
||||
true: "web:truncate",
|
||||
},
|
||||
bold: {
|
||||
true: "font-bold",
|
||||
},
|
||||
underline: {
|
||||
true: "underline",
|
||||
},
|
||||
strikeThrough: {
|
||||
true: "line-through",
|
||||
},
|
||||
size: {
|
||||
"2xs": "text-2xs",
|
||||
xs: "text-xs",
|
||||
sm: "text-sm",
|
||||
md: "text-base",
|
||||
lg: "text-lg",
|
||||
xl: "text-xl",
|
||||
"2xl": "text-2xl",
|
||||
"3xl": "text-3xl",
|
||||
"4xl": "text-4xl",
|
||||
"5xl": "text-5xl",
|
||||
"6xl": "text-6xl",
|
||||
},
|
||||
sub: {
|
||||
true: "text-xs",
|
||||
},
|
||||
italic: {
|
||||
true: "italic",
|
||||
},
|
||||
highlight: {
|
||||
true: "bg-yellow-500",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
type ILinkProps = React.ComponentProps<typeof UILink> &
|
||||
VariantProps<typeof linkStyle> & { className?: string };
|
||||
|
||||
const Link = React.forwardRef<React.ElementRef<typeof UILink>, ILinkProps>(
|
||||
({ className, ...props }, ref) => {
|
||||
return (
|
||||
<UILink
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={linkStyle({ class: className })}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
type ILinkTextProps = React.ComponentProps<typeof UILink.Text> &
|
||||
VariantProps<typeof linkTextStyle> & { className?: string };
|
||||
|
||||
const LinkText = React.forwardRef<
|
||||
React.ElementRef<typeof UILink.Text>,
|
||||
ILinkTextProps
|
||||
>(({ className, size = "md", ...props }, ref) => {
|
||||
return (
|
||||
<UILink.Text
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={linkTextStyle({
|
||||
class: className,
|
||||
size,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
Link.displayName = "Link";
|
||||
LinkText.displayName = "LinkText";
|
||||
|
||||
export { Link, LinkText };
|
@ -1,48 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
||||
import { Text as RNText } from 'react-native';
|
||||
import { textStyle } from './styles';
|
||||
|
||||
type ITextProps = React.ComponentProps<typeof RNText> &
|
||||
VariantProps<typeof textStyle>;
|
||||
|
||||
const Text = React.forwardRef<React.ElementRef<typeof RNText>, ITextProps>(
|
||||
(
|
||||
{
|
||||
className,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
size = 'md',
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
return (
|
||||
<RNText
|
||||
className={textStyle({
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
size,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Text.displayName = 'Text';
|
||||
|
||||
export { Text };
|
@ -1,45 +0,0 @@
|
||||
import React from 'react';
|
||||
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
||||
import { textStyle } from './styles';
|
||||
|
||||
type ITextProps = React.ComponentProps<'span'> & VariantProps<typeof textStyle>;
|
||||
|
||||
const Text = React.forwardRef<React.ElementRef<'span'>, ITextProps>(
|
||||
(
|
||||
{
|
||||
className,
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
size = 'md',
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
...props
|
||||
}: { className?: string } & ITextProps,
|
||||
ref
|
||||
) => {
|
||||
return (
|
||||
<span
|
||||
className={textStyle({
|
||||
isTruncated,
|
||||
bold,
|
||||
underline,
|
||||
strikeThrough,
|
||||
size,
|
||||
sub,
|
||||
italic,
|
||||
highlight,
|
||||
class: className,
|
||||
})}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Text.displayName = 'Text';
|
||||
|
||||
export { Text };
|
@ -1,47 +0,0 @@
|
||||
import { tva } from "@gluestack-ui/nativewind-utils/tva";
|
||||
import { isWeb } from "@gluestack-ui/nativewind-utils/IsWeb";
|
||||
|
||||
const baseStyle = isWeb
|
||||
? "font-sans tracking-sm my-0 bg-transparent border-0 box-border display-inline list-none margin-0 padding-0 position-relative text-start no-underline whitespace-pre-wrap word-wrap-break-word"
|
||||
: "";
|
||||
|
||||
export const textStyle = tva({
|
||||
base: `text-typography-700 font-body ${baseStyle}`,
|
||||
|
||||
variants: {
|
||||
isTruncated: {
|
||||
true: "web:truncate",
|
||||
},
|
||||
bold: {
|
||||
true: "font-bold",
|
||||
},
|
||||
underline: {
|
||||
true: "underline",
|
||||
},
|
||||
strikeThrough: {
|
||||
true: "line-through",
|
||||
},
|
||||
size: {
|
||||
"2xs": "text-2xs",
|
||||
xs: "text-xs",
|
||||
sm: "text-sm",
|
||||
md: "text-base",
|
||||
lg: "text-lg",
|
||||
xl: "text-xl",
|
||||
"2xl": "text-2xl",
|
||||
"3xl": "text-3xl",
|
||||
"4xl": "text-4xl",
|
||||
"5xl": "text-5xl",
|
||||
"6xl": "text-6xl",
|
||||
},
|
||||
sub: {
|
||||
true: "text-xs",
|
||||
},
|
||||
italic: {
|
||||
true: "italic",
|
||||
},
|
||||
highlight: {
|
||||
true: "bg-yellow-500",
|
||||
},
|
||||
},
|
||||
});
|
@ -1,24 +0,0 @@
|
||||
import React from 'react';
|
||||
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
||||
import { View } from 'react-native';
|
||||
|
||||
import { vstackStyle } from './styles';
|
||||
|
||||
type IVStackProps = React.ComponentProps<typeof View> &
|
||||
VariantProps<typeof vstackStyle>;
|
||||
|
||||
const VStack = React.forwardRef<React.ElementRef<typeof View>, IVStackProps>(
|
||||
({ className, space, reversed, ...props }, ref) => {
|
||||
return (
|
||||
<View
|
||||
className={vstackStyle({ space, reversed, class: className })}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
VStack.displayName = 'VStack';
|
||||
|
||||
export { VStack };
|
@ -1,23 +0,0 @@
|
||||
import React from 'react';
|
||||
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
||||
|
||||
import { vstackStyle } from './styles';
|
||||
|
||||
type IVStackProps = React.ComponentProps<'div'> &
|
||||
VariantProps<typeof vstackStyle>;
|
||||
|
||||
const VStack = React.forwardRef<React.ElementRef<'div'>, IVStackProps>(
|
||||
({ className, space, reversed, ...props }, ref) => {
|
||||
return (
|
||||
<div
|
||||
className={vstackStyle({ space, reversed, class: className })}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
VStack.displayName = 'VStack';
|
||||
|
||||
export { VStack };
|
@ -1,25 +0,0 @@
|
||||
import { isWeb } from '@gluestack-ui/nativewind-utils/IsWeb';
|
||||
import { tva } from '@gluestack-ui/nativewind-utils/tva';
|
||||
|
||||
const baseStyle = isWeb
|
||||
? 'flex flex-col relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none'
|
||||
: '';
|
||||
|
||||
export const vstackStyle = tva({
|
||||
base: `flex-col ${baseStyle}`,
|
||||
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',
|
||||
},
|
||||
reversed: {
|
||||
true: 'flex-col-reverse',
|
||||
},
|
||||
},
|
||||
});
|
Loading…
Reference in new issue