@nativetail/ui 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nativetail/ui",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "",
5
5
  "main": "src/index.ts",
6
6
  "scripts": {},
@@ -27,24 +27,25 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@hookform/resolvers": "^3.6.0",
30
- "@nativetail/core": "^0.0.2",
30
+ "@nativetail/core": "^0.0.5",
31
31
  "@shopify/flash-list": "^1.7.0",
32
32
  "countries-list": "^3.1.0",
33
33
  "expo-blur": "^13.0.2",
34
34
  "expo-linear-gradient": "~13.0.2",
35
+ "lucide-react-native": "^0.427.0",
35
36
  "moti": "^0.29.0",
36
37
  "react": "18.2.0",
37
38
  "react-hook-form": "^7.51.0",
38
39
  "react-native": "0.74.3",
39
40
  "react-native-actions-sheet": "^0.9.6",
40
41
  "react-native-gesture-handler": "^2.17.1",
42
+ "react-native-mask-text": "^0.14.2",
41
43
  "react-native-reanimated": "~3.10.1",
42
44
  "react-native-safe-area-context": "4.10.1",
43
45
  "tailwind-merge": "^2.3.0",
44
46
  "zustand": "^4.5.2"
45
47
  },
46
48
  "devDependencies": {
47
- "metro-react-native-babel-preset": "^0.77.0",
48
49
  "tailwindcss": "^3.4.4"
49
50
  },
50
51
  "private": false
@@ -86,7 +86,7 @@ const ActionSheetItem = ({
86
86
  <Button
87
87
  variant="link"
88
88
  className={cn(
89
- "w-full items-center opacity-100 active:opacity-50 text-[16px] h-14 text-blue-500 rounded-none border-b ",
89
+ "w-full items-center opacity-100 active:opacity-50 text-sm h-14 text-blue-500 rounded-none border-b ",
90
90
  last ? "border-transparent" : "border-muted/15",
91
91
  className
92
92
  )}
@@ -1,4 +1,4 @@
1
- import { Text, View } from "@nativetail/core";
1
+ import { cn, Text, View } from "@nativetail/core";
2
2
  import { forwardRef } from "react";
3
3
  import { Button } from "../button";
4
4
  import { Dialog, DialogMethods } from "../dialog";
@@ -10,11 +10,26 @@ export type AlertDialogProps = {
10
10
  title?: string;
11
11
  description?: string;
12
12
  useBlur?: boolean;
13
+ confirmClassName?: string;
14
+ cancelClassName?: string;
15
+ confirmText?: string;
16
+ cancelText?: string;
13
17
  };
14
18
  export type AlertDialogRef = DialogMethods;
15
19
  export const AlertDialog = forwardRef<DialogMethods, AlertDialogProps>(
16
20
  function AlertDialog(
17
- { containerClassName, onConfirm, title, description, useBlur, onCancel },
21
+ {
22
+ containerClassName,
23
+ onConfirm,
24
+ confirmText = "Confirm",
25
+ cancelText = "Cancel",
26
+ cancelClassName,
27
+ confirmClassName,
28
+ title,
29
+ description,
30
+ useBlur,
31
+ onCancel,
32
+ },
18
33
  ref
19
34
  ) {
20
35
  return (
@@ -39,17 +54,23 @@ export const AlertDialog = forwardRef<DialogMethods, AlertDialogProps>(
39
54
  <View className="flex-row items-center border-t border-muted/15">
40
55
  <Button
41
56
  variant="link"
42
- className="flex-1 active:opacity-75 text-foreground rounded-none"
57
+ className={cn(
58
+ "flex-1 active:opacity-75 text-foreground rounded-none",
59
+ cancelClassName
60
+ )}
43
61
  onPress={onCancel}
44
62
  >
45
- Cancel
63
+ {cancelText}
46
64
  </Button>
47
65
  <Button
48
66
  variant="link"
49
- className="flex-1 border active:opacity-75 border-transparent rounded-none border-l-muted/15"
67
+ className={cn(
68
+ "flex-1 border active:opacity-75 border-transparent rounded-none border-l-muted/15",
69
+ cancelClassName
70
+ )}
50
71
  onPress={onConfirm}
51
72
  >
52
- Confirm
73
+ {confirmText}
53
74
  </Button>
54
75
  </View>
55
76
  </Dialog>
@@ -8,6 +8,7 @@ import {
8
8
  mergeClasses,
9
9
  Pressable,
10
10
  separateClasses,
11
+ useColor,
11
12
  useTw,
12
13
  VariantProps,
13
14
  } from "@nativetail/core";
@@ -15,11 +16,11 @@ import { MotiPressableProps } from "moti/interactions";
15
16
  import { useComponentTheme } from "../../utils/component-theme";
16
17
 
17
18
  const buttonVariants = cva(
18
- "flex-row gap-2 items-center justify-center rounded text-sm font-medium hover:opacity-90 active:opacity-80 opacity-100 select-none",
19
+ "flex-row gap-2 items-center justify-center rounded text-sm font-medium hover:opacity-90 active:opacity-50 duration-30 opacity-100 select-none",
19
20
  {
20
21
  variants: {
21
22
  variant: {
22
- default: "bg-primary text-foreground ",
23
+ default: "bg-primary text-primary-foreground ",
23
24
  destructive: "bg-red-500 text-foreground ",
24
25
  outline: "border border-muted/15 text-foreground bg-black/0 ",
25
26
  secondary: "bg-secondary text-foreground ",
@@ -84,9 +85,10 @@ export type ButtonProps = MotiPressableProps &
84
85
  const Button = (passedProps: ButtonProps) => {
85
86
  const componentTheme = useComponentTheme();
86
87
  const buttonProps = componentTheme?.Button || {};
87
- const {
88
+ let {
88
89
  text,
89
90
  children,
91
+
90
92
  isLoading,
91
93
  disabled,
92
94
  variant,
@@ -101,6 +103,7 @@ const Button = (passedProps: ButtonProps) => {
101
103
  ...buttonProps,
102
104
  ...passedProps,
103
105
  };
106
+ children = children || text;
104
107
  const tw = useTw();
105
108
  const className = cn(buttonProps.className, passedProps.className);
106
109
 
@@ -128,24 +131,26 @@ const Button = (passedProps: ButtonProps) => {
128
131
  const { textClasses } = separateClasses(variantClass);
129
132
 
130
133
  return (
131
- <Pressable
132
- disabled={disabled || loading}
133
- className={variantClass}
134
- {...props}
135
- >
136
- {leftElement}
137
- {loading && (
138
- <ActivityIndicator
139
- className={mergeClasses(
140
- "mr-2 h-5 w-5 text-foreground ",
141
- textClasses,
142
- loadingIndicatorClassName
143
- )}
144
- />
145
- )}
146
- {children}
147
- {rightElement}
148
- </Pressable>
134
+ <>
135
+ <Pressable
136
+ disabled={disabled || loading}
137
+ className={variantClass}
138
+ {...props}
139
+ >
140
+ {leftElement}
141
+ {loading && (
142
+ <ActivityIndicator
143
+ className={mergeClasses(
144
+ "mr-2 h-5 w-5 text-primary-foreground ",
145
+ textClasses,
146
+ loadingIndicatorClassName
147
+ )}
148
+ />
149
+ )}
150
+ {children}
151
+ {rightElement}
152
+ </Pressable>
153
+ </>
149
154
  );
150
155
  };
151
156
  export { Button };
@@ -0,0 +1,72 @@
1
+ import { cn, Text, useTw, View } from "@nativetail/core";
2
+ import { Pressable } from "react-native";
3
+ import { Button, ButtonProps } from "../button";
4
+
5
+ type CardProps = {
6
+ renderHeader?: () => React.ReactNode;
7
+ title?: string;
8
+ subtitle?: string;
9
+ description?: string;
10
+ titleClassname?: string;
11
+ subtitleClassName?: string;
12
+ descriptionClassName?: string;
13
+ containerClassName?: string;
14
+ contentClassName?: string;
15
+ buttonProps?: ButtonProps;
16
+ onPress?: () => void;
17
+ renderFooter?: () => React.ReactNode;
18
+ renderContent?: () => React.ReactNode;
19
+ };
20
+ export function Card({
21
+ description,
22
+ descriptionClassName,
23
+ renderHeader,
24
+ subtitle,
25
+ subtitleClassName,
26
+ title,
27
+ titleClassname,
28
+ contentClassName,
29
+ buttonProps,
30
+ onPress,
31
+ renderFooter,
32
+ containerClassName,
33
+ ...props
34
+ }: CardProps) {
35
+ const tw = useTw();
36
+ const renderContent = () => {
37
+ if (props.renderContent) {
38
+ return props.renderContent();
39
+ }
40
+ return (
41
+ <View className={cn("p-1 gap-1", contentClassName)}>
42
+ <Text className={cn("text-lg font-medium", titleClassname)}>
43
+ {title}
44
+ </Text>
45
+ <Text className={cn("text-sm ", subtitleClassName)}>{subtitle}</Text>
46
+ <Text
47
+ className={cn(
48
+ "text-xs text-muted tracking-widest",
49
+ descriptionClassName
50
+ )}
51
+ >
52
+ {description}
53
+ </Text>
54
+ {buttonProps && <Button {...buttonProps} />}
55
+ </View>
56
+ );
57
+ };
58
+ return (
59
+ <Pressable
60
+ style={tw.style(
61
+ "bg-card p-3 rounded-xl border border-muted/15",
62
+ containerClassName
63
+ )}
64
+ onPress={onPress}
65
+ disabled={!onPress}
66
+ >
67
+ {renderHeader && renderHeader()}
68
+ {renderContent()}
69
+ {renderFooter && renderFooter()}
70
+ </Pressable>
71
+ );
72
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./card";
2
+ export * from "./stat-card";
3
+ export * from "./info-card";
@@ -0,0 +1,113 @@
1
+ import { cn, Pressable, Text, useColor, View } from "@nativetail/core";
2
+ import { EllipsisVertical } from "lucide-react-native";
3
+ import { useRef } from "react";
4
+ import {
5
+ ActionSheet,
6
+ ActionSheetProps,
7
+ ActionSheetRef,
8
+ } from "../actions-sheet";
9
+
10
+ type InfoCardProps = {
11
+ containerClassname?: string;
12
+ renderIcon?: () => React.ReactNode;
13
+ renderContent?: () => React.ReactNode;
14
+ contentClassName?: string;
15
+ title?: string;
16
+ subtitle?: string;
17
+ titleClassname?: string;
18
+ subtitleClassName?: string;
19
+ description?: string;
20
+ descriptionClassName?: string;
21
+ actions?: ActionSheetProps["options"];
22
+ renderRight?: () => React.ReactNode;
23
+ onPress?: () => void;
24
+ dotsClassname?: string;
25
+ textContentClassname?: string;
26
+ };
27
+ export function InfoCard({
28
+ containerClassname,
29
+ renderIcon,
30
+ subtitle,
31
+ title,
32
+ titleClassname,
33
+ subtitleClassName,
34
+ description,
35
+ descriptionClassName,
36
+ actions,
37
+ onPress,
38
+ dotsClassname,
39
+ contentClassName,
40
+ textContentClassname,
41
+ ...props
42
+ }: InfoCardProps) {
43
+ const actionSheetRef = useRef<ActionSheetRef>(null);
44
+ const renderRight = () => {
45
+ if (props.renderRight) {
46
+ return props.renderRight();
47
+ }
48
+ if (actions)
49
+ return (
50
+ <View className="flex-row gap-1">
51
+ <>
52
+ <Pressable
53
+ className={cn(
54
+ "p-1.5 w-7 h-7 items-center justify-center border rounded-full border-muted/15 active:scale-95 scale-100",
55
+ dotsClassname
56
+ )}
57
+ onPress={() => {
58
+ actionSheetRef.current?.show();
59
+ }}
60
+ >
61
+ <EllipsisVertical color={useColor("foreground")} />
62
+ </Pressable>
63
+ <ActionSheet
64
+ onCancel={() => {
65
+ actionSheetRef.current?.hide();
66
+ }}
67
+ options={actions.map((action) => ({
68
+ ...action,
69
+ onPress: () => {
70
+ actionSheetRef.current?.hide();
71
+ action.onPress();
72
+ },
73
+ }))}
74
+ ref={actionSheetRef}
75
+ />
76
+ </>
77
+ </View>
78
+ );
79
+ };
80
+ const renderContent = () => {
81
+ if (props.renderContent) {
82
+ return props.renderContent();
83
+ }
84
+ return (
85
+ <View className={textContentClassname}>
86
+ <Text className={cn("text-sm font-medium", titleClassname)}>
87
+ {title}
88
+ </Text>
89
+ <Text className={cn("text-[13px] text-muted", subtitleClassName)}>
90
+ {subtitle}
91
+ </Text>
92
+ <Text className={cn("text-xs text-muted/65", descriptionClassName)}>
93
+ {description}
94
+ </Text>
95
+ </View>
96
+ );
97
+ };
98
+ return (
99
+ <Pressable
100
+ className={cn(
101
+ "flex-row items-center w-full justify-between ",
102
+ containerClassname
103
+ )}
104
+ disabled={!onPress}
105
+ >
106
+ <View className={cn("flex-row gap-2 items-center p-2", contentClassName)}>
107
+ {renderIcon && renderIcon()}
108
+ {renderContent()}
109
+ </View>
110
+ {renderRight()}
111
+ </Pressable>
112
+ );
113
+ }
@@ -0,0 +1,46 @@
1
+ import { cn, View } from "@nativetail/core";
2
+
3
+ type StatCardProps = {
4
+ renderIcon?: () => React.ReactNode;
5
+ renderTitle?: () => React.ReactNode;
6
+ renderValue?: () => React.ReactNode;
7
+ title?: string;
8
+ value?: string;
9
+ Icon?: React.ReactNode;
10
+ containerClassName?: string;
11
+ };
12
+ export function StatCard(props: StatCardProps) {
13
+ const renderIcon = () => {
14
+ if (props.Icon) return <View className="mb-2">{props.Icon}</View>;
15
+ if (!props.renderIcon) return null;
16
+ return props.renderIcon();
17
+ };
18
+ const renderTitle = () => {
19
+ if (!props.renderTitle)
20
+ return <View className="text-xs text-muted/80">{props.title}</View>;
21
+ return props.renderTitle();
22
+ };
23
+ const renderValue = () => {
24
+ if (!props.renderValue)
25
+ return (
26
+ <View className="text-xl font-medium text-foreground">
27
+ {props.value}
28
+ </View>
29
+ );
30
+ return props.renderValue();
31
+ };
32
+ return (
33
+ <View
34
+ className={cn(
35
+ "p-3 rounded-xl gap-0.5 bg-card border justify-between border-muted/15",
36
+ props.containerClassName
37
+ )}
38
+ >
39
+ {renderIcon()}
40
+ <View className="gap-0.5">
41
+ {renderValue()}
42
+ {renderTitle()}
43
+ </View>
44
+ </View>
45
+ );
46
+ }
@@ -0,0 +1,43 @@
1
+ import { cn, Pressable, useColor } from "@nativetail/core";
2
+ import { CheckIcon } from "lucide-react-native";
3
+
4
+ type CheckProps = {
5
+ checked: boolean;
6
+ onChange: (checked: boolean) => void;
7
+ className?: string;
8
+ activeClassName?: string;
9
+ inactiveCheckColor?: string;
10
+ activeCheckColor?: string;
11
+ };
12
+ export function Check({
13
+ checked,
14
+ onChange,
15
+ className,
16
+ activeClassName,
17
+ inactiveCheckColor,
18
+ activeCheckColor,
19
+ ...props
20
+ }: CheckProps) {
21
+ return (
22
+ <Pressable
23
+ className={cn(
24
+ "border w-6 h-6 p-1 items-center justify-center rounded-lg border-muted/15 bg-card",
25
+ className,
26
+ checked ? "bg-primary " + activeClassName : ""
27
+ )}
28
+ aria-checked={checked}
29
+ accessibilityRole="switch"
30
+ aria-label="Check"
31
+ {...props}
32
+ onPress={() => onChange(!checked)}
33
+ >
34
+ <CheckIcon
35
+ color={useColor(
36
+ checked
37
+ ? activeCheckColor || "card"
38
+ : inactiveCheckColor || "primary/35"
39
+ )}
40
+ />
41
+ </Pressable>
42
+ );
43
+ }
@@ -0,0 +1,23 @@
1
+ type CollapsibleProps = {
2
+ onChange: (checked: boolean) => void;
3
+ className?: string;
4
+ };
5
+ function CollapsibleRoot({ onChange, className, ...props }: CollapsibleProps) {
6
+ return <></>;
7
+ }
8
+ type CollapsibleTriggerProps = {};
9
+
10
+ const CollapsibleTrigger = ({ ...props }: CollapsibleTriggerProps) => {
11
+ return <></>;
12
+ };
13
+ type CollapsibleContentProps = {};
14
+
15
+ const CollapsibleContent = ({ ...props }: CollapsibleContentProps) => {
16
+ return <></>;
17
+ };
18
+
19
+ export const Collapsible = {
20
+ Trigger: CollapsibleTrigger,
21
+ Content: CollapsibleContent,
22
+ Root: CollapsibleRoot,
23
+ };
@@ -1,6 +1,6 @@
1
- import { TextInput, View, cn, useTw } from "@nativetail/core";
1
+ import { TextInput, View, cn, useColor, useTw } from "@nativetail/core";
2
+ import { Minus, Plus } from "lucide-react-native";
2
3
  import { useCallback, useRef } from "react";
3
- import { Iconify } from "react-native-iconify";
4
4
  import { Button } from "../button";
5
5
  export type CounterProps = {
6
6
  value: number;
@@ -48,11 +48,7 @@ export function Counter({
48
48
  )}
49
49
  >
50
50
  <CounterButton disabled={!!(min && value <= min)} onPress={decrement}>
51
- <Iconify
52
- icon="ic:round-minus"
53
- size={15}
54
- color={tw.color("foreground")}
55
- />
51
+ <Minus size={15} color={useColor("foreground")} />
56
52
  </CounterButton>
57
53
  <View className="flex-1 h-full">
58
54
  <TextInput
@@ -62,11 +58,7 @@ export function Counter({
62
58
  />
63
59
  </View>
64
60
  <CounterButton disabled={!!(max && value >= max)} onPress={increment}>
65
- <Iconify
66
- icon="ic:round-plus"
67
- size={15}
68
- color={tw.color("foreground")}
69
- />
61
+ <Plus size={15} color={useColor("foreground")} />
70
62
  </CounterButton>
71
63
  </View>
72
64
  );
@@ -14,3 +14,7 @@ export * from "./progress";
14
14
  export * from "./counter";
15
15
  export * from "./tabs";
16
16
  export * from "./form-builder";
17
+ export * from "./check";
18
+ export * from "./card";
19
+ export * from "./indicator";
20
+ export * from "./loader-dialog";
@@ -0,0 +1,15 @@
1
+ import { cn, View } from "@nativetail/core";
2
+
3
+ type IndicatorProps = {
4
+ className?: string;
5
+ size?: number;
6
+ color?: string;
7
+ Icon?: React.ReactNode;
8
+ };
9
+ export function Indicator({ className, size, color, Icon }: IndicatorProps) {
10
+ return (
11
+ <View className={cn("w-4 h-4 rounded-full bg-primary", className)}>
12
+ {Icon}
13
+ </View>
14
+ );
15
+ }
@@ -8,6 +8,7 @@ import { Input, InputProps } from "./input";
8
8
 
9
9
  import { countries, ICountry } from "countries-list";
10
10
  import { FloatingInput } from "./floating-input";
11
+ import { ChevronDown } from "lucide-react-native";
11
12
  type CountryType = ICountry & {
12
13
  code: string;
13
14
  };
@@ -97,7 +98,7 @@ const SelectCountry = ({
97
98
  <Text>
98
99
  <Text className="mr-1">{flag}</Text>+{selectedCountry.phone?.[0]}
99
100
  </Text>
100
- <Iconify icon="mingcute:down-line" size={24} color="gray" />
101
+ <ChevronDown size={24} color="gray" />
101
102
  </Pressable>
102
103
  <CountryBottomSheet
103
104
  selectedCountry={selectedCountry}
@@ -1,5 +1,5 @@
1
- import { Pressable, useTw } from "@nativetail/core";
2
- import { Iconify } from "react-native-iconify";
1
+ import { Pressable, useColor } from "@nativetail/core";
2
+ import { Eye, EyeOff } from "lucide-react-native";
3
3
 
4
4
  export default function ShowPassword({
5
5
  showPassword,
@@ -8,24 +8,15 @@ export default function ShowPassword({
8
8
  showPassword: boolean;
9
9
  setShowPassword: (showPassword: boolean) => void;
10
10
  }) {
11
- const tw = useTw();
12
11
  return (
13
12
  <Pressable
14
13
  onPress={() => setShowPassword(!showPassword)}
15
14
  className="absolute right-2 bottom-2"
16
15
  >
17
16
  {showPassword ? (
18
- <Iconify
19
- icon="solar:eye-linear"
20
- size={20}
21
- color={tw.color("foreground")}
22
- />
17
+ <Eye size={20} color={useColor("foreground")} />
23
18
  ) : (
24
- <Iconify
25
- icon="solar:eye-closed-linear"
26
- size={20}
27
- color={tw.color("foreground")}
28
- />
19
+ <EyeOff size={20} color={useColor("foreground")} />
29
20
  )}
30
21
  </Pressable>
31
22
  );
@@ -0,0 +1,35 @@
1
+ import { ActivityIndicator, cn, useColor } from "@nativetail/core";
2
+ import { forwardRef } from "react";
3
+ import { Dialog, DialogMethods, DialogProps } from "../dialog";
4
+
5
+ export type LoaderProps = Omit<DialogProps, "children"> & {
6
+ activityIndicatorProps?: React.ComponentProps<typeof ActivityIndicator>;
7
+ children?: React.ReactNode;
8
+ };
9
+
10
+ export const Loader = forwardRef<DialogMethods, LoaderProps>(function Loader(
11
+ { ...props },
12
+ ref
13
+ ) {
14
+ return (
15
+ <Dialog
16
+ ref={ref}
17
+ closable={false}
18
+ {...props}
19
+ contentClassName={cn(
20
+ "items-center justify-center p-4 w-24 h-24",
21
+ props?.contentClassName
22
+ )}
23
+ >
24
+ {props?.children || (
25
+ <ActivityIndicator
26
+ size="large"
27
+ color={useColor("primary")}
28
+ {...props?.activityIndicatorProps}
29
+ />
30
+ )}
31
+ </Dialog>
32
+ );
33
+ });
34
+
35
+ export type Loader = DialogMethods;
@@ -3,6 +3,7 @@ import {
3
3
  Pressable,
4
4
  PressableProps,
5
5
  Text,
6
+ useColor,
6
7
  useTw,
7
8
  View,
8
9
  } from "@nativetail/core";
@@ -10,6 +11,7 @@ import { Dropdown } from "../dropdown";
10
11
  import { memo, useCallback, useMemo } from "react";
11
12
  import { Iconify } from "react-native-iconify";
12
13
  import { Control, Controller, Path } from "react-hook-form";
14
+ import { CheckCheck, CheckIcon, ChevronDown } from "lucide-react-native";
13
15
 
14
16
  export type MultiSelectProps<T = Record<string, any>> = PressableProps & {
15
17
  containerClassName?: string;
@@ -150,11 +152,7 @@ const SelectTrigger = memo(
150
152
  {selectedOptions.length == 0 && placeholder && (
151
153
  <Text className="text-muted">{placeholder}</Text>
152
154
  )}
153
- <Iconify
154
- icon="solar:alt-arrow-down-outline"
155
- size={20}
156
- color={tw.color("foreground")}
157
- />
155
+ <ChevronDown size={20} color={useColor("foreground")} />
158
156
  </Dropdown.Trigger>
159
157
 
160
158
  {error && <Text className="text-sm text-danger">{error}</Text>}
@@ -195,13 +193,7 @@ const SelectItem = memo(
195
193
  <Text className="text-sm text-foreground">{label}</Text>
196
194
  {icon}
197
195
  </View>
198
- {isActive && (
199
- <Iconify
200
- icon="lucide:check"
201
- size={16}
202
- color={tw.color("foreground")}
203
- />
204
- )}
196
+ {isActive && <CheckIcon size={16} color={useColor("foreground")} />}
205
197
  </Dropdown.Item>
206
198
  );
207
199
  }
@@ -1,8 +1,15 @@
1
- import { cn, PressableProps, Text, useTw, View } from "@nativetail/core";
2
- import { Dropdown } from "../dropdown";
1
+ import {
2
+ cn,
3
+ PressableProps,
4
+ Text,
5
+ useColor,
6
+ useTw,
7
+ View,
8
+ } from "@nativetail/core";
9
+ import { CheckCheck, CheckIcon, ChevronDown } from "lucide-react-native";
3
10
  import { memo, useCallback, useMemo } from "react";
4
- import { Iconify } from "react-native-iconify";
5
11
  import { Control, Controller, Path } from "react-hook-form";
12
+ import { Dropdown } from "../dropdown";
6
13
 
7
14
  export type SelectProps<T = Record<string, any>> = PressableProps & {
8
15
  containerClassName?: string;
@@ -124,11 +131,7 @@ const SelectTrigger = memo(
124
131
  {!selectedOption && placeholder && (
125
132
  <Text className="text-muted">{placeholder}</Text>
126
133
  )}
127
- <Iconify
128
- icon="solar:alt-arrow-down-outline"
129
- size={20}
130
- color={tw.color("foreground")}
131
- />
134
+ <ChevronDown size={20} color={useColor("foreground")} />
132
135
  </Dropdown.Trigger>
133
136
  {error && <Text className="text-sm text-danger">{error}</Text>}
134
137
  </>
@@ -167,13 +170,7 @@ const SelectItem = memo(
167
170
  <Text className="text-sm text-foreground">{label}</Text>
168
171
  {icon}
169
172
  </View>
170
- {isActive && (
171
- <Iconify
172
- icon="lucide:check"
173
- size={16}
174
- color={tw.color("foreground")}
175
- />
176
- )}
173
+ {isActive && <CheckIcon size={16} color={useColor("foreground")} />}
177
174
  </Dropdown.Item>
178
175
  );
179
176
  }
@@ -8,7 +8,7 @@ import {
8
8
  } from "@nativetail/core";
9
9
 
10
10
  const switchVariants = cva(
11
- "rounded-full bg-card justify-center border p-0.5 items-start",
11
+ "rounded-full bg-card justify-center border border-muted/15 p-0.5 items-start",
12
12
  {
13
13
  variants: {
14
14
  size: {
@@ -51,7 +51,7 @@ export function Switch({
51
51
  <Pressable
52
52
  className={cn(
53
53
  className,
54
- checked ? "bg-primary/35 " + containerActiveClass : ""
54
+ checked ? "bg-primary " + containerActiveClass : ""
55
55
  )}
56
56
  aria-checked={checked}
57
57
  accessibilityRole="switch"
@@ -63,6 +63,7 @@ export function Switch({
63
63
  className={cn(
64
64
  `rounded-full bg-primary aspect-square h-full`,
65
65
  indicatorClassName,
66
+ checked ? "bg-card" : "",
66
67
  x
67
68
  )}
68
69
  animated
@@ -1,8 +1,13 @@
1
- import { cn, Pressable, Text, useTw, View } from "@nativetail/core";
1
+ import { cn, Pressable, Text, useColor, useTw, View } from "@nativetail/core";
2
+ import {
3
+ CheckCircle2,
4
+ Info,
5
+ OctagonAlert,
6
+ OctagonX,
7
+ } from "lucide-react-native";
2
8
  import { AnimatePresence } from "moti";
3
9
  import { useCallback, useEffect, useState } from "react";
4
10
  import { Modal } from "react-native";
5
- import { Iconify } from "react-native-iconify";
6
11
  import { useSafeAreaInsets } from "react-native-safe-area-context";
7
12
  import { create } from "zustand";
8
13
  type ToastType = {
@@ -50,7 +55,6 @@ const useToastState = create<ToastStore>((set) => ({
50
55
  let timeouts = new Map<string, NodeJS.Timeout>();
51
56
  export const showToast = (toast: InsertToastType) => {
52
57
  const id = Math.random().toString(36).substring(7);
53
- console.log(id);
54
58
  useToastState.getState().addToast({ ...toast, id });
55
59
  return id;
56
60
  };
@@ -108,8 +112,8 @@ const Toast = (
108
112
  className={cn(
109
113
  "absolute w-full h-full bg-black/15 left-0 justify-start z-50 gap-2",
110
114
  toast.position.includes("top")
111
- ? `pt-[${safeInsets.top + 10}px]`
112
- : `pb-[${safeInsets.bottom + 10}px]`
115
+ ? `pt-[${safeInsets.top + 10}px] top-0`
116
+ : `pb-[${safeInsets.bottom + 10}px] bottom-0 justify-end`
113
117
  )}
114
118
  onPress={close}
115
119
  >
@@ -140,30 +144,10 @@ const BaseToast = (
140
144
  }, [toast.id]);
141
145
 
142
146
  const Icons = {
143
- success: (
144
- <Iconify
145
- icon="lets-icons:check-fill"
146
- size={20}
147
- color={tw.color("success")}
148
- />
149
- ),
150
- danger: (
151
- <Iconify icon="uis:times-circle" size={20} color={tw.color("danger")} />
152
- ),
153
- info: (
154
- <Iconify
155
- icon="fluent:info-16-filled"
156
- size={20}
157
- color={tw.color("info")}
158
- />
159
- ),
160
- warning: (
161
- <Iconify
162
- icon="fluent:warning-16-filled"
163
- size={20}
164
- color={tw.color("warning")}
165
- />
166
- ),
147
+ success: <CheckCircle2 size={20} color={useColor("success")} />,
148
+ danger: <OctagonX size={20} color={useColor("danger")} />,
149
+ info: <Info size={20} color={useColor("info")} />,
150
+ warning: <OctagonAlert size={20} color={useColor("warning")} />,
167
151
  };
168
152
 
169
153
  const Icon = toast.icon || Icons[toast.type];
@@ -1,3 +1,4 @@
1
+
1
2
  module.exports = {
2
3
  theme: {
3
4
  screens: {
@@ -9,7 +10,10 @@ module.exports = {
9
10
  },
10
11
  extend: {
11
12
  colors: {
12
- primary: "#43D386",
13
+ primary: {
14
+ DEFAULT: "#43D386",
15
+ foreground: "#000",
16
+ },
13
17
  secondary: '#EBB461',
14
18
  background: '#F2F2F2',
15
19
  card: '#fff',
@@ -26,4 +30,4 @@ module.exports = {
26
30
  }
27
31
  },
28
32
  },
29
- };
33
+ };