@nativetail/ui 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +5 -0
- package/babel.config.js +3 -0
- package/package.json +50 -0
- package/src/components/actions-sheet/index.tsx +98 -0
- package/src/components/alert-dialog/index.tsx +58 -0
- package/src/components/blur/index.tsx +15 -0
- package/src/components/bottom-sheet/index.tsx +46 -0
- package/src/components/button/index.tsx +109 -0
- package/src/components/chip/index.tsx +74 -0
- package/src/components/counter/index.tsx +101 -0
- package/src/components/dialog/index.tsx +111 -0
- package/src/components/dropdown/index.tsx +252 -0
- package/src/components/index.ts +14 -0
- package/src/components/input/floating-input.tsx +74 -0
- package/src/components/input/index.ts +2 -0
- package/src/components/input/input.tsx +41 -0
- package/src/components/progress/index.tsx +28 -0
- package/src/components/select/index.tsx +141 -0
- package/src/components/stepper/index.tsx +31 -0
- package/src/components/switch/index.tsx +72 -0
- package/src/components/toast/index.tsx +101 -0
- package/src/index.ts +1 -0
- package/tailwind.config.js +25 -0
- package/tsconfig.json +18 -0
@@ -0,0 +1,101 @@
|
|
1
|
+
import { BlurView } from "expo-blur";
|
2
|
+
import { cn, Pressable, Text, useTw, View } from "@nativetail/core";
|
3
|
+
import { useEffect } from "react";
|
4
|
+
import { create } from "zustand";
|
5
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
6
|
+
import { AnimatePresence } from "moti";
|
7
|
+
import { Blur } from "../blur";
|
8
|
+
type ToastType = {
|
9
|
+
message: string;
|
10
|
+
content?: string;
|
11
|
+
id: string;
|
12
|
+
timeout?: number;
|
13
|
+
position?: "top" | "bottom";
|
14
|
+
containerClassName?: string;
|
15
|
+
};
|
16
|
+
type InsertToastType = Omit<ToastType, "id">;
|
17
|
+
type ToastStore = {
|
18
|
+
toasts: ToastType[];
|
19
|
+
addToast: (toast: ToastType) => void;
|
20
|
+
removeToast: (id: string) => void;
|
21
|
+
};
|
22
|
+
const useToastState = create<ToastStore>((set) => ({
|
23
|
+
toasts: [],
|
24
|
+
addToast: (toast) => set((state) => ({ toasts: [...state.toasts, toast] })),
|
25
|
+
removeToast: (id) =>
|
26
|
+
set((state) => ({
|
27
|
+
toasts: state.toasts.filter((toast) => toast.id !== id),
|
28
|
+
})),
|
29
|
+
}));
|
30
|
+
let timeouts = new Map<string, NodeJS.Timeout>();
|
31
|
+
export const showToast = (toast: InsertToastType) => {
|
32
|
+
const id = Math.random().toString(36).substring(7);
|
33
|
+
useToastState.getState().addToast({ ...toast, id });
|
34
|
+
return id;
|
35
|
+
};
|
36
|
+
export function Toaster() {
|
37
|
+
const toasts = useToastState((state) => state.toasts);
|
38
|
+
return (
|
39
|
+
<AnimatePresence exitBeforeEnter>
|
40
|
+
{toasts.map((toast, index) => (
|
41
|
+
<Toast key={toast.id} index={index} {...toast} />
|
42
|
+
))}
|
43
|
+
</AnimatePresence>
|
44
|
+
);
|
45
|
+
}
|
46
|
+
|
47
|
+
const Toast = (
|
48
|
+
toast: ToastType & {
|
49
|
+
index: number;
|
50
|
+
}
|
51
|
+
) => {
|
52
|
+
const tw = useTw();
|
53
|
+
useEffect(() => {
|
54
|
+
const id = setTimeout(() => {
|
55
|
+
useToastState.getState().removeToast(toast.id);
|
56
|
+
}, toast.timeout || 5000);
|
57
|
+
timeouts.set(toast.id, id);
|
58
|
+
return () => {
|
59
|
+
clearTimeout(timeouts.get(toast.id)!);
|
60
|
+
timeouts.delete(toast.id);
|
61
|
+
};
|
62
|
+
}, [toast.id]);
|
63
|
+
const safeInsets = useSafeAreaInsets();
|
64
|
+
return (
|
65
|
+
<View
|
66
|
+
className={cn(
|
67
|
+
"absolute w-full top-0 left-0 items-center justify-center z-50 ",
|
68
|
+
toast.position === "top"
|
69
|
+
? `top-[${safeInsets.top + 10}px]`
|
70
|
+
: `bottom-[${safeInsets.bottom + 10}px]`,
|
71
|
+
toast.containerClassName
|
72
|
+
)}
|
73
|
+
animated
|
74
|
+
>
|
75
|
+
<Pressable
|
76
|
+
onPress={() => {
|
77
|
+
useToastState.getState().removeToast(toast.id);
|
78
|
+
}}
|
79
|
+
className="w-full items-center justify-center active:scale-95 scale-100 px-4"
|
80
|
+
>
|
81
|
+
<View
|
82
|
+
className={cn(
|
83
|
+
`bg-card/95 border border-muted/15 px-6 py-3 in:opacity-0 opacity-100 in:-translate-y-16 out:-translate-y-16 out:opacity-0 in:scale-0 scale-100 out:scale-0 rounded-full overflow-hidden max-w-sm w-full `,
|
84
|
+
`translate-y-0`
|
85
|
+
)}
|
86
|
+
animated
|
87
|
+
>
|
88
|
+
<Blur
|
89
|
+
style={tw`absolute top-0 left-0 rounded-xl flex-1 bg-card/50 rounded-full`}
|
90
|
+
/>
|
91
|
+
<Text className="font-medium text-[16px] text-foreground">
|
92
|
+
{toast.message}
|
93
|
+
</Text>
|
94
|
+
{toast.content && (
|
95
|
+
<Text className="text-sm text-muted">{toast.content}</Text>
|
96
|
+
)}
|
97
|
+
</View>
|
98
|
+
</Pressable>
|
99
|
+
</View>
|
100
|
+
);
|
101
|
+
};
|
package/src/index.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export * from "./components";
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module.exports = {
|
2
|
+
theme: {
|
3
|
+
screens: {
|
4
|
+
sm: "380px",
|
5
|
+
md: "420px",
|
6
|
+
lg: "680px",
|
7
|
+
// or maybe name them after devices for `tablet:flex-row`
|
8
|
+
tablet: "1024px",
|
9
|
+
},
|
10
|
+
extend: {
|
11
|
+
colors: {
|
12
|
+
primary: "#43D386",
|
13
|
+
secondary: '#EBB461',
|
14
|
+
background: '#F2F2F2',
|
15
|
+
card: '#fff',
|
16
|
+
foreground: '#000',
|
17
|
+
muted: '#383737',
|
18
|
+
success: '#4CAF50',
|
19
|
+
danger: '#F44336',
|
20
|
+
warning: '#FFC107',
|
21
|
+
info: '#00BCD4',
|
22
|
+
},
|
23
|
+
},
|
24
|
+
},
|
25
|
+
};
|
package/tsconfig.json
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
"strict": false,
|
4
|
+
"esModuleInterop": true,
|
5
|
+
"noUncheckedIndexedAccess": true,
|
6
|
+
"noImplicitOverride": true,
|
7
|
+
"skipLibCheck": true,
|
8
|
+
"rootDir": "./",
|
9
|
+
"outDir": "./dist/esm",
|
10
|
+
"lib": ["ES2019"],
|
11
|
+
"target": "ES2019",
|
12
|
+
"declaration": true,
|
13
|
+
"moduleResolution": "node",
|
14
|
+
"jsx": "react-jsx",
|
15
|
+
"stripInternal": true
|
16
|
+
},
|
17
|
+
"exclude": ["./dist", "**/*.spec.ts"]
|
18
|
+
}
|