@liedsonc/core-auth-kit 2.1.4 → 2.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +802 -0
- package/dist/components/auth-card.d.ts +10 -0
- package/dist/components/auth-card.d.ts.map +1 -0
- package/dist/components/auth-card.js +10 -0
- package/dist/components/auth-form.d.ts +10 -0
- package/dist/components/auth-form.d.ts.map +1 -0
- package/dist/components/auth-form.js +21 -0
- package/dist/components/error-message.d.ts +6 -0
- package/dist/components/error-message.d.ts.map +1 -0
- package/dist/components/error-message.js +8 -0
- package/dist/components/form-field.d.ts +9 -0
- package/dist/components/form-field.d.ts.map +1 -0
- package/dist/components/form-field.js +7 -0
- package/dist/components/index.d.ts +9 -0
- package/dist/components/index.d.ts.map +1 -0
- package/{components/index.ts → dist/components/index.js} +8 -8
- package/dist/components/loading-spinner.d.ts +5 -0
- package/dist/components/loading-spinner.d.ts.map +1 -0
- package/dist/components/loading-spinner.js +6 -0
- package/dist/components/oauth-buttons.d.ts +11 -0
- package/dist/components/oauth-buttons.d.ts.map +1 -0
- package/dist/components/oauth-buttons.js +14 -0
- package/dist/components/password-input.d.ts +8 -0
- package/dist/components/password-input.d.ts.map +1 -0
- package/dist/components/password-input.js +36 -0
- package/dist/components/success-message.d.ts +6 -0
- package/dist/components/success-message.d.ts.map +1 -0
- package/dist/components/success-message.js +8 -0
- package/dist/components/ui/button.d.ts +12 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +33 -0
- package/dist/components/ui/card.d.ts +9 -0
- package/dist/components/ui/card.d.ts.map +1 -0
- package/dist/components/ui/card.js +16 -0
- package/dist/components/ui/input.d.ts +4 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/input.js +8 -0
- package/dist/components/ui/label.d.ts +6 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/label.js +10 -0
- package/dist/context.d.ts +8 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +13 -0
- package/dist/hooks/use-auth.d.ts +22 -0
- package/dist/hooks/use-auth.d.ts.map +1 -0
- package/dist/hooks/use-auth.js +112 -0
- package/dist/hooks/use-oauth.d.ts +6 -0
- package/dist/hooks/use-oauth.d.ts.map +1 -0
- package/dist/hooks/use-oauth.js +18 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/pages/forgot-password/index.d.ts +2 -0
- package/dist/pages/forgot-password/index.d.ts.map +1 -0
- package/dist/pages/forgot-password/index.js +30 -0
- package/dist/pages/index.d.ts +6 -0
- package/dist/pages/index.d.ts.map +1 -0
- package/{pages/index.ts → dist/pages/index.js} +5 -5
- package/dist/pages/login/index.d.ts +2 -0
- package/dist/pages/login/index.d.ts.map +1 -0
- package/dist/pages/login/index.js +45 -0
- package/dist/pages/register/index.d.ts +2 -0
- package/dist/pages/register/index.d.ts.map +1 -0
- package/dist/pages/register/index.js +59 -0
- package/dist/pages/reset-password/index.d.ts +2 -0
- package/dist/pages/reset-password/index.d.ts.map +1 -0
- package/dist/pages/reset-password/index.js +48 -0
- package/dist/pages/verify-email/index.d.ts +2 -0
- package/dist/pages/verify-email/index.d.ts.map +1 -0
- package/dist/pages/verify-email/index.js +47 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/types/index.d.ts +60 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +5 -0
- package/package.json +15 -11
- package/components/auth-card.tsx +0 -49
- package/components/auth-form.tsx +0 -53
- package/components/error-message.tsx +0 -24
- package/components/form-field.tsx +0 -39
- package/components/loading-spinner.tsx +0 -19
- package/components/oauth-buttons.tsx +0 -49
- package/components/password-input.tsx +0 -93
- package/components/success-message.tsx +0 -24
- package/components/ui/button.tsx +0 -52
- package/components/ui/card.tsx +0 -75
- package/components/ui/input.tsx +0 -21
- package/components/ui/label.tsx +0 -25
- package/context.tsx +0 -26
- package/hooks/use-auth.ts +0 -131
- package/hooks/use-oauth.ts +0 -25
- package/index.ts +0 -28
- package/pages/forgot-password/index.tsx +0 -83
- package/pages/login/index.tsx +0 -119
- package/pages/register/index.tsx +0 -149
- package/pages/reset-password/index.tsx +0 -133
- package/pages/verify-email/index.tsx +0 -143
- package/types/index.ts +0 -34
- package/utils.ts +0 -6
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export type OAuthProvider = "google" | "apple";
|
|
3
|
+
export interface AuthError {
|
|
4
|
+
code: string;
|
|
5
|
+
message: string;
|
|
6
|
+
}
|
|
7
|
+
export interface AuthSession {
|
|
8
|
+
user: {
|
|
9
|
+
id: string;
|
|
10
|
+
email?: string;
|
|
11
|
+
};
|
|
12
|
+
expiresAt?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface AuthClient {
|
|
15
|
+
login: (email: string, password: string) => Promise<{
|
|
16
|
+
success: true;
|
|
17
|
+
} | {
|
|
18
|
+
success: false;
|
|
19
|
+
error: AuthError;
|
|
20
|
+
}>;
|
|
21
|
+
register: (email: string, password: string) => Promise<{
|
|
22
|
+
success: true;
|
|
23
|
+
} | {
|
|
24
|
+
success: false;
|
|
25
|
+
error: AuthError;
|
|
26
|
+
}>;
|
|
27
|
+
logout: () => Promise<void>;
|
|
28
|
+
forgotPassword: (email: string) => Promise<{
|
|
29
|
+
success: true;
|
|
30
|
+
} | {
|
|
31
|
+
success: false;
|
|
32
|
+
error: AuthError;
|
|
33
|
+
}>;
|
|
34
|
+
resetPassword: (token: string, newPassword: string) => Promise<{
|
|
35
|
+
success: true;
|
|
36
|
+
} | {
|
|
37
|
+
success: false;
|
|
38
|
+
error: AuthError;
|
|
39
|
+
}>;
|
|
40
|
+
verifyEmail: (token: string) => Promise<{
|
|
41
|
+
success: true;
|
|
42
|
+
} | {
|
|
43
|
+
success: false;
|
|
44
|
+
error: AuthError;
|
|
45
|
+
}>;
|
|
46
|
+
getSession?: () => Promise<AuthSession | null>;
|
|
47
|
+
}
|
|
48
|
+
export type AuthFormState = "idle" | "loading" | "success" | "error";
|
|
49
|
+
export interface AuthUIConfig {
|
|
50
|
+
authClient: AuthClient;
|
|
51
|
+
oauthProviders?: {
|
|
52
|
+
provider: OAuthProvider;
|
|
53
|
+
enabled: boolean;
|
|
54
|
+
}[];
|
|
55
|
+
logo?: ReactNode;
|
|
56
|
+
redirectAfterLogin?: string;
|
|
57
|
+
redirectAfterRegister?: string;
|
|
58
|
+
redirectAfterReset?: string;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE/C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAC9G,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IACjH,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IACrG,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IACzH,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAClG,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CAChD;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAErE,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,cAAc,CAAC,EAAE;QAAE,QAAQ,EAAE,aAAa,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IACjE,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAG7C,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC"}
|
package/dist/utils.js
ADDED
package/package.json
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liedsonc/core-auth-kit",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.6",
|
|
4
4
|
"description": "Production-ready authentication UI package for Next.js App Router",
|
|
5
|
-
"main": "./index.
|
|
6
|
-
"types": "./index.ts",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
8
|
-
".":
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
9
13
|
"./styles": "./styles/index.css"
|
|
10
14
|
},
|
|
11
15
|
"bin": {
|
|
@@ -13,16 +17,16 @@
|
|
|
13
17
|
"@liedsonc/core-auth-kit": "./bin/init.js"
|
|
14
18
|
},
|
|
15
19
|
"files": [
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"**/*.js",
|
|
20
|
+
"dist",
|
|
21
|
+
"styles",
|
|
22
|
+
"bin",
|
|
20
23
|
"templates"
|
|
21
24
|
],
|
|
22
25
|
"scripts": {
|
|
23
|
-
"build": "tsc
|
|
26
|
+
"build": "tsc -p tsconfig.build.json",
|
|
24
27
|
"type-check": "tsc --noEmit",
|
|
25
|
-
"publish": "npm publish --access public"
|
|
28
|
+
"publish": "npm publish --access public",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
26
30
|
},
|
|
27
31
|
"dependencies": {
|
|
28
32
|
"@radix-ui/react-label": "^2.1.0",
|
|
@@ -59,4 +63,4 @@
|
|
|
59
63
|
"url": "https://github.com/liedsonc/core-auth-kit/issues"
|
|
60
64
|
},
|
|
61
65
|
"homepage": "https://github.com/liedsonc/core-auth-kit#readme"
|
|
62
|
-
}
|
|
66
|
+
}
|
package/components/auth-card.tsx
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
Card,
|
|
5
|
-
CardContent,
|
|
6
|
-
CardDescription,
|
|
7
|
-
CardFooter,
|
|
8
|
-
CardHeader,
|
|
9
|
-
CardTitle,
|
|
10
|
-
} from "./ui/card";
|
|
11
|
-
import { useAuthUIConfig } from "../context";
|
|
12
|
-
import { cn } from "../utils";
|
|
13
|
-
import "../styles/index.css";
|
|
14
|
-
|
|
15
|
-
export interface AuthCardProps {
|
|
16
|
-
title: string;
|
|
17
|
-
subtitle?: string;
|
|
18
|
-
children: React.ReactNode;
|
|
19
|
-
footer?: React.ReactNode;
|
|
20
|
-
className?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function AuthCard({
|
|
24
|
-
title,
|
|
25
|
-
subtitle,
|
|
26
|
-
children,
|
|
27
|
-
footer,
|
|
28
|
-
className,
|
|
29
|
-
}: AuthCardProps) {
|
|
30
|
-
const config = useAuthUIConfig();
|
|
31
|
-
|
|
32
|
-
return (
|
|
33
|
-
<Card className={cn("auth-ui-card", className)}>
|
|
34
|
-
<CardHeader className="space-y-1">
|
|
35
|
-
{config.logo && (
|
|
36
|
-
<div className="flex justify-center mb-2" aria-hidden="true">
|
|
37
|
-
{config.logo}
|
|
38
|
-
</div>
|
|
39
|
-
)}
|
|
40
|
-
<CardTitle className="text-center">{title}</CardTitle>
|
|
41
|
-
{subtitle && (
|
|
42
|
-
<CardDescription className="text-center">{subtitle}</CardDescription>
|
|
43
|
-
)}
|
|
44
|
-
</CardHeader>
|
|
45
|
-
<CardContent>{children}</CardContent>
|
|
46
|
-
{footer && <CardFooter className="flex flex-col gap-2">{footer}</CardFooter>}
|
|
47
|
-
</Card>
|
|
48
|
-
);
|
|
49
|
-
}
|
package/components/auth-form.tsx
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
import { cn } from "../utils";
|
|
5
|
-
|
|
6
|
-
export interface AuthFormProps
|
|
7
|
-
extends Omit<React.FormHTMLAttributes<HTMLFormElement>, "onSubmit"> {
|
|
8
|
-
onSubmit: (e: React.FormEvent<HTMLFormElement>) => void | Promise<void>;
|
|
9
|
-
loading?: boolean;
|
|
10
|
-
error?: string;
|
|
11
|
-
children: React.ReactNode;
|
|
12
|
-
className?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function AuthForm({
|
|
16
|
-
onSubmit,
|
|
17
|
-
loading = false,
|
|
18
|
-
error,
|
|
19
|
-
children,
|
|
20
|
-
className,
|
|
21
|
-
...props
|
|
22
|
-
}: AuthFormProps) {
|
|
23
|
-
const [submitting, setSubmitting] = React.useState(false);
|
|
24
|
-
const isDisabled = loading || submitting;
|
|
25
|
-
|
|
26
|
-
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
27
|
-
e.preventDefault();
|
|
28
|
-
if (isDisabled) return;
|
|
29
|
-
setSubmitting(true);
|
|
30
|
-
try {
|
|
31
|
-
await onSubmit(e);
|
|
32
|
-
} finally {
|
|
33
|
-
setSubmitting(false);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
return (
|
|
38
|
-
<form
|
|
39
|
-
onSubmit={handleSubmit}
|
|
40
|
-
noValidate
|
|
41
|
-
className={cn("space-y-4", className)}
|
|
42
|
-
aria-busy={isDisabled}
|
|
43
|
-
{...props}
|
|
44
|
-
>
|
|
45
|
-
{error && (
|
|
46
|
-
<p role="alert" className="text-sm text-destructive">
|
|
47
|
-
{error}
|
|
48
|
-
</p>
|
|
49
|
-
)}
|
|
50
|
-
{children}
|
|
51
|
-
</form>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { cn } from "../utils";
|
|
4
|
-
|
|
5
|
-
export function ErrorMessage({
|
|
6
|
-
children,
|
|
7
|
-
className,
|
|
8
|
-
id,
|
|
9
|
-
}: {
|
|
10
|
-
children: React.ReactNode;
|
|
11
|
-
className?: string;
|
|
12
|
-
id?: string;
|
|
13
|
-
}) {
|
|
14
|
-
if (!children) return null;
|
|
15
|
-
return (
|
|
16
|
-
<p
|
|
17
|
-
id={id}
|
|
18
|
-
role="alert"
|
|
19
|
-
className={cn("text-sm text-destructive", className)}
|
|
20
|
-
>
|
|
21
|
-
{children}
|
|
22
|
-
</p>
|
|
23
|
-
);
|
|
24
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { Label } from "./ui/label";
|
|
4
|
-
import { cn } from "../utils";
|
|
5
|
-
|
|
6
|
-
export function FormField({
|
|
7
|
-
label,
|
|
8
|
-
htmlFor,
|
|
9
|
-
error,
|
|
10
|
-
children,
|
|
11
|
-
required,
|
|
12
|
-
className,
|
|
13
|
-
}: {
|
|
14
|
-
label: string;
|
|
15
|
-
htmlFor: string;
|
|
16
|
-
error?: string;
|
|
17
|
-
children: React.ReactNode;
|
|
18
|
-
required?: boolean;
|
|
19
|
-
className?: string;
|
|
20
|
-
}) {
|
|
21
|
-
return (
|
|
22
|
-
<div className={cn("space-y-2", className)}>
|
|
23
|
-
<Label htmlFor={htmlFor}>
|
|
24
|
-
{label}
|
|
25
|
-
{required && (
|
|
26
|
-
<span className="text-destructive ml-0.5" aria-hidden="true">
|
|
27
|
-
*
|
|
28
|
-
</span>
|
|
29
|
-
)}
|
|
30
|
-
</Label>
|
|
31
|
-
{children}
|
|
32
|
-
{error && (
|
|
33
|
-
<p id={`${htmlFor}-error`} role="alert" className="text-sm text-destructive">
|
|
34
|
-
{error}
|
|
35
|
-
</p>
|
|
36
|
-
)}
|
|
37
|
-
</div>
|
|
38
|
-
);
|
|
39
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { cn } from "../utils";
|
|
4
|
-
|
|
5
|
-
export function LoadingSpinner({
|
|
6
|
-
className,
|
|
7
|
-
"aria-label": ariaLabel = "Loading",
|
|
8
|
-
}: {
|
|
9
|
-
className?: string;
|
|
10
|
-
"aria-label"?: string;
|
|
11
|
-
}) {
|
|
12
|
-
return (
|
|
13
|
-
<span
|
|
14
|
-
role="status"
|
|
15
|
-
aria-label={ariaLabel}
|
|
16
|
-
className={cn("inline-block size-5 animate-spin rounded-full border-2 border-current border-t-transparent", className)}
|
|
17
|
-
/>
|
|
18
|
-
);
|
|
19
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { Button } from "./ui/button";
|
|
4
|
-
import { useOAuth } from "../hooks/use-oauth";
|
|
5
|
-
import { cn } from "../utils";
|
|
6
|
-
import type { OAuthProvider } from "../types";
|
|
7
|
-
|
|
8
|
-
const providerLabels: Record<OAuthProvider, string> = {
|
|
9
|
-
google: "Continue with Google",
|
|
10
|
-
apple: "Continue with Apple",
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export function OAuthButtons({
|
|
14
|
-
providers,
|
|
15
|
-
loadingProvider,
|
|
16
|
-
onSignIn,
|
|
17
|
-
className,
|
|
18
|
-
}: {
|
|
19
|
-
providers: { provider: OAuthProvider; enabled: boolean }[];
|
|
20
|
-
loadingProvider: OAuthProvider | null;
|
|
21
|
-
onSignIn: (provider: OAuthProvider) => void | Promise<void>;
|
|
22
|
-
className?: string;
|
|
23
|
-
}) {
|
|
24
|
-
const enabled = providers.filter((p) => p.enabled);
|
|
25
|
-
|
|
26
|
-
if (enabled.length === 0) return null;
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<div className={cn("space-y-2", className)}>
|
|
30
|
-
{enabled.map(({ provider }) => (
|
|
31
|
-
<Button
|
|
32
|
-
key={provider}
|
|
33
|
-
type="button"
|
|
34
|
-
variant="outline"
|
|
35
|
-
className="w-full"
|
|
36
|
-
disabled={!!loadingProvider}
|
|
37
|
-
onClick={() => onSignIn(provider)}
|
|
38
|
-
aria-busy={loadingProvider === provider}
|
|
39
|
-
>
|
|
40
|
-
{loadingProvider === provider ? (
|
|
41
|
-
<span className="inline-block size-4 animate-spin rounded-full border-2 border-current border-t-transparent" />
|
|
42
|
-
) : (
|
|
43
|
-
providerLabels[provider]
|
|
44
|
-
)}
|
|
45
|
-
</Button>
|
|
46
|
-
))}
|
|
47
|
-
</div>
|
|
48
|
-
);
|
|
49
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
import { Input } from "./ui/input";
|
|
5
|
-
import { Button } from "./ui/button";
|
|
6
|
-
import { cn } from "../utils";
|
|
7
|
-
|
|
8
|
-
function getStrength(value: string): 0 | 1 | 2 | 3 {
|
|
9
|
-
if (!value) return 0;
|
|
10
|
-
let s = 0;
|
|
11
|
-
if (value.length >= 8) s++;
|
|
12
|
-
if (value.length >= 12) s++;
|
|
13
|
-
if (/[A-Z]/.test(value) && /[a-z]/.test(value) && /\d/.test(value)) s++;
|
|
14
|
-
return Math.min(s, 3) as 0 | 1 | 2 | 3;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface PasswordInputProps
|
|
18
|
-
extends Omit<React.ComponentProps<typeof Input>, "type"> {
|
|
19
|
-
showStrength?: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const PasswordInput = React.forwardRef<HTMLInputElement, PasswordInputProps>(
|
|
23
|
-
({ className, showStrength = false, ...props }, ref) => {
|
|
24
|
-
const [show, setShow] = React.useState(false);
|
|
25
|
-
const [value, setValue] = React.useState("");
|
|
26
|
-
const id = React.useId();
|
|
27
|
-
const strength = showStrength ? getStrength(value) : 0;
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<div className="space-y-1.5">
|
|
31
|
-
<div className="relative">
|
|
32
|
-
<Input
|
|
33
|
-
ref={ref}
|
|
34
|
-
type={show ? "text" : "password"}
|
|
35
|
-
autoComplete="current-password"
|
|
36
|
-
aria-describedby={showStrength ? `${id}-strength` : undefined}
|
|
37
|
-
className={cn("pr-10", className)}
|
|
38
|
-
{...props}
|
|
39
|
-
value={props.value ?? value}
|
|
40
|
-
onChange={(e) => {
|
|
41
|
-
setValue(e.target.value);
|
|
42
|
-
props.onChange?.(e);
|
|
43
|
-
}}
|
|
44
|
-
/>
|
|
45
|
-
<Button
|
|
46
|
-
type="button"
|
|
47
|
-
variant="ghost"
|
|
48
|
-
size="icon"
|
|
49
|
-
className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
|
|
50
|
-
aria-label={show ? "Hide password" : "Show password"}
|
|
51
|
-
aria-pressed={show}
|
|
52
|
-
onClick={() => setShow((p) => !p)}
|
|
53
|
-
tabIndex={-1}
|
|
54
|
-
>
|
|
55
|
-
<span className="text-xs font-medium" aria-hidden="true">
|
|
56
|
-
{show ? "Hide" : "Show"}
|
|
57
|
-
</span>
|
|
58
|
-
</Button>
|
|
59
|
-
</div>
|
|
60
|
-
{showStrength && value && (
|
|
61
|
-
<div
|
|
62
|
-
id={`${id}-strength`}
|
|
63
|
-
role="progressbar"
|
|
64
|
-
aria-valuenow={strength}
|
|
65
|
-
aria-valuemin={0}
|
|
66
|
-
aria-valuemax={3}
|
|
67
|
-
aria-label="Password strength"
|
|
68
|
-
className="flex gap-1"
|
|
69
|
-
>
|
|
70
|
-
{[1, 2, 3].map((i) => (
|
|
71
|
-
<span
|
|
72
|
-
key={i}
|
|
73
|
-
className={cn(
|
|
74
|
-
"h-1 flex-1 rounded-full",
|
|
75
|
-
i <= strength
|
|
76
|
-
? strength === 1
|
|
77
|
-
? "bg-destructive"
|
|
78
|
-
: strength === 2
|
|
79
|
-
? "bg-amber-500"
|
|
80
|
-
: "bg-green-500"
|
|
81
|
-
: "bg-muted"
|
|
82
|
-
)}
|
|
83
|
-
/>
|
|
84
|
-
))}
|
|
85
|
-
</div>
|
|
86
|
-
)}
|
|
87
|
-
</div>
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
);
|
|
91
|
-
PasswordInput.displayName = "PasswordInput";
|
|
92
|
-
|
|
93
|
-
export { PasswordInput };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { cn } from "../utils";
|
|
4
|
-
|
|
5
|
-
export function SuccessMessage({
|
|
6
|
-
children,
|
|
7
|
-
className,
|
|
8
|
-
id,
|
|
9
|
-
}: {
|
|
10
|
-
children: React.ReactNode;
|
|
11
|
-
className?: string;
|
|
12
|
-
id?: string;
|
|
13
|
-
}) {
|
|
14
|
-
if (!children) return null;
|
|
15
|
-
return (
|
|
16
|
-
<p
|
|
17
|
-
id={id}
|
|
18
|
-
role="status"
|
|
19
|
-
className={cn("text-sm text-green-600 dark:text-green-400", className)}
|
|
20
|
-
>
|
|
21
|
-
{children}
|
|
22
|
-
</p>
|
|
23
|
-
);
|
|
24
|
-
}
|
package/components/ui/button.tsx
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
3
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
|
-
import { cn } from "../../utils";
|
|
5
|
-
|
|
6
|
-
const buttonVariants = cva(
|
|
7
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
8
|
-
{
|
|
9
|
-
variants: {
|
|
10
|
-
variant: {
|
|
11
|
-
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
12
|
-
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
13
|
-
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
14
|
-
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
15
|
-
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
16
|
-
link: "text-primary underline-offset-4 hover:underline",
|
|
17
|
-
},
|
|
18
|
-
size: {
|
|
19
|
-
default: "h-10 px-4 py-2",
|
|
20
|
-
sm: "h-9 rounded-md px-3",
|
|
21
|
-
lg: "h-11 rounded-md px-8",
|
|
22
|
-
icon: "h-10 w-10",
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
defaultVariants: {
|
|
26
|
-
variant: "default",
|
|
27
|
-
size: "default",
|
|
28
|
-
},
|
|
29
|
-
}
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
export interface ButtonProps
|
|
33
|
-
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
34
|
-
VariantProps<typeof buttonVariants> {
|
|
35
|
-
asChild?: boolean;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
39
|
-
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
40
|
-
const Comp = asChild ? Slot : "button";
|
|
41
|
-
return (
|
|
42
|
-
<Comp
|
|
43
|
-
className={cn(buttonVariants({ variant, size, className }))}
|
|
44
|
-
ref={ref}
|
|
45
|
-
{...props}
|
|
46
|
-
/>
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
Button.displayName = "Button";
|
|
51
|
-
|
|
52
|
-
export { Button, buttonVariants };
|
package/components/ui/card.tsx
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { cn } from "../../utils";
|
|
3
|
-
|
|
4
|
-
const Card = React.forwardRef<
|
|
5
|
-
HTMLDivElement,
|
|
6
|
-
React.HTMLAttributes<HTMLDivElement>
|
|
7
|
-
>(({ className, ...props }, ref) => (
|
|
8
|
-
<div
|
|
9
|
-
ref={ref}
|
|
10
|
-
className={cn(
|
|
11
|
-
"rounded-lg border border-border bg-card text-card-foreground shadow-sm",
|
|
12
|
-
className
|
|
13
|
-
)}
|
|
14
|
-
{...props}
|
|
15
|
-
/>
|
|
16
|
-
));
|
|
17
|
-
Card.displayName = "Card";
|
|
18
|
-
|
|
19
|
-
const CardHeader = React.forwardRef<
|
|
20
|
-
HTMLDivElement,
|
|
21
|
-
React.HTMLAttributes<HTMLDivElement>
|
|
22
|
-
>(({ className, ...props }, ref) => (
|
|
23
|
-
<div
|
|
24
|
-
ref={ref}
|
|
25
|
-
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
|
26
|
-
{...props}
|
|
27
|
-
/>
|
|
28
|
-
));
|
|
29
|
-
CardHeader.displayName = "CardHeader";
|
|
30
|
-
|
|
31
|
-
const CardTitle = React.forwardRef<
|
|
32
|
-
HTMLParagraphElement,
|
|
33
|
-
React.HTMLAttributes<HTMLHeadingElement>
|
|
34
|
-
>(({ className, ...props }, ref) => (
|
|
35
|
-
<h3
|
|
36
|
-
ref={ref}
|
|
37
|
-
className={cn("text-2xl font-semibold leading-none tracking-tight", className)}
|
|
38
|
-
{...props}
|
|
39
|
-
/>
|
|
40
|
-
));
|
|
41
|
-
CardTitle.displayName = "CardTitle";
|
|
42
|
-
|
|
43
|
-
const CardDescription = React.forwardRef<
|
|
44
|
-
HTMLParagraphElement,
|
|
45
|
-
React.HTMLAttributes<HTMLParagraphElement>
|
|
46
|
-
>(({ className, ...props }, ref) => (
|
|
47
|
-
<p
|
|
48
|
-
ref={ref}
|
|
49
|
-
className={cn("text-sm text-muted-foreground", className)}
|
|
50
|
-
{...props}
|
|
51
|
-
/>
|
|
52
|
-
));
|
|
53
|
-
CardDescription.displayName = "CardDescription";
|
|
54
|
-
|
|
55
|
-
const CardContent = React.forwardRef<
|
|
56
|
-
HTMLDivElement,
|
|
57
|
-
React.HTMLAttributes<HTMLDivElement>
|
|
58
|
-
>(({ className, ...props }, ref) => (
|
|
59
|
-
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
|
60
|
-
));
|
|
61
|
-
CardContent.displayName = "CardContent";
|
|
62
|
-
|
|
63
|
-
const CardFooter = React.forwardRef<
|
|
64
|
-
HTMLDivElement,
|
|
65
|
-
React.HTMLAttributes<HTMLDivElement>
|
|
66
|
-
>(({ className, ...props }, ref) => (
|
|
67
|
-
<div
|
|
68
|
-
ref={ref}
|
|
69
|
-
className={cn("flex items-center p-6 pt-0", className)}
|
|
70
|
-
{...props}
|
|
71
|
-
/>
|
|
72
|
-
));
|
|
73
|
-
CardFooter.displayName = "CardFooter";
|
|
74
|
-
|
|
75
|
-
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
|
package/components/ui/input.tsx
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { cn } from "../../utils";
|
|
3
|
-
|
|
4
|
-
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
|
5
|
-
({ className, type, ...props }, ref) => {
|
|
6
|
-
return (
|
|
7
|
-
<input
|
|
8
|
-
type={type}
|
|
9
|
-
className={cn(
|
|
10
|
-
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
11
|
-
className
|
|
12
|
-
)}
|
|
13
|
-
ref={ref}
|
|
14
|
-
{...props}
|
|
15
|
-
/>
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
);
|
|
19
|
-
Input.displayName = "Input";
|
|
20
|
-
|
|
21
|
-
export { Input };
|
package/components/ui/label.tsx
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
5
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
6
|
-
import { cn } from "../../utils";
|
|
7
|
-
|
|
8
|
-
const labelVariants = cva(
|
|
9
|
-
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
10
|
-
);
|
|
11
|
-
|
|
12
|
-
const Label = React.forwardRef<
|
|
13
|
-
React.ElementRef<typeof LabelPrimitive.Root>,
|
|
14
|
-
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
|
15
|
-
VariantProps<typeof labelVariants>
|
|
16
|
-
>(({ className, ...props }, ref) => (
|
|
17
|
-
<LabelPrimitive.Root
|
|
18
|
-
ref={ref}
|
|
19
|
-
className={cn(labelVariants(), className)}
|
|
20
|
-
{...props}
|
|
21
|
-
/>
|
|
22
|
-
));
|
|
23
|
-
Label.displayName = LabelPrimitive.Root.displayName;
|
|
24
|
-
|
|
25
|
-
export { Label };
|