@proveanything/smartlinks-auth-ui 0.1.0
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 +323 -0
- package/dist/api.d.ts +44 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +105 -0
- package/dist/components/AuthContainer.d.ts +12 -0
- package/dist/components/AuthContainer.d.ts.map +1 -0
- package/dist/components/AuthContainer.js +46 -0
- package/dist/components/AuthUIPreview.d.ts +11 -0
- package/dist/components/AuthUIPreview.d.ts.map +1 -0
- package/dist/components/AuthUIPreview.js +10 -0
- package/dist/components/EmailAuthForm.d.ts +14 -0
- package/dist/components/EmailAuthForm.d.ts.map +1 -0
- package/dist/components/EmailAuthForm.js +20 -0
- package/dist/components/PasswordResetForm.d.ts +13 -0
- package/dist/components/PasswordResetForm.d.ts.map +1 -0
- package/dist/components/PasswordResetForm.js +37 -0
- package/dist/components/PhoneAuthForm.d.ts +11 -0
- package/dist/components/PhoneAuthForm.d.ts.map +1 -0
- package/dist/components/PhoneAuthForm.js +20 -0
- package/dist/components/ProtectedRoute.d.ts +9 -0
- package/dist/components/ProtectedRoute.d.ts.map +1 -0
- package/dist/components/ProtectedRoute.js +20 -0
- package/dist/components/ProviderButtons.d.ts +12 -0
- package/dist/components/ProviderButtons.d.ts.map +1 -0
- package/dist/components/ProviderButtons.js +8 -0
- package/dist/context/AuthContext.d.ts +20 -0
- package/dist/context/AuthContext.d.ts.map +1 -0
- package/dist/context/AuthContext.js +113 -0
- package/dist/index.css +2 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.css +2 -0
- package/dist/index.esm.css.map +1 -0
- package/dist/index.esm.js +840 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +867 -0
- package/dist/index.js.map +1 -0
- package/dist/smartlinks.d.ts +65 -0
- package/dist/smartlinks.d.ts.map +1 -0
- package/dist/smartlinks.js +141 -0
- package/dist/types.d.ts +101 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/utils/tokenStorage.d.ts +14 -0
- package/dist/utils/tokenStorage.d.ts.map +1 -0
- package/dist/utils/tokenStorage.js +71 -0
- package/package.json +57 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import './AuthForm.css';
|
|
4
|
+
export const PasswordResetForm = ({ onSubmit, onBack, loading, error, success, token, }) => {
|
|
5
|
+
const [email, setEmail] = useState('');
|
|
6
|
+
const [password, setPassword] = useState('');
|
|
7
|
+
const [confirmPassword, setConfirmPassword] = useState('');
|
|
8
|
+
const [passwordError, setPasswordError] = useState('');
|
|
9
|
+
const handleSubmit = async (e) => {
|
|
10
|
+
e.preventDefault();
|
|
11
|
+
if (token) {
|
|
12
|
+
// Reset password with token
|
|
13
|
+
if (password !== confirmPassword) {
|
|
14
|
+
setPasswordError('Passwords do not match');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (password.length < 6) {
|
|
18
|
+
setPasswordError('Password must be at least 6 characters');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
setPasswordError('');
|
|
22
|
+
await onSubmit(password, confirmPassword);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
// Request password reset
|
|
26
|
+
await onSubmit(email);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
if (success) {
|
|
30
|
+
return (_jsxs("div", { className: "auth-form", children: [_jsxs("div", { className: "auth-form-header", children: [_jsx("div", { style: { textAlign: 'center', marginBottom: '1rem' }, children: _jsxs("svg", { width: "64", height: "64", viewBox: "0 0 64 64", fill: "none", style: { margin: '0 auto' }, children: [_jsx("circle", { cx: "32", cy: "32", r: "32", fill: "#10b981", fillOpacity: "0.1" }), _jsx("path", { d: "M20 32l8 8 16-16", stroke: "#10b981", strokeWidth: "4", strokeLinecap: "round", strokeLinejoin: "round" })] }) }), _jsx("h2", { className: "auth-form-title", children: token ? 'Password reset!' : 'Check your email' }), _jsx("p", { className: "auth-form-subtitle", children: token
|
|
31
|
+
? 'Your password has been successfully reset. You can now sign in with your new password.'
|
|
32
|
+
: `We've sent password reset instructions to ${email}` })] }), _jsx("button", { type: "button", className: "auth-button auth-button-primary", onClick: onBack, children: "Back to Sign in" })] }));
|
|
33
|
+
}
|
|
34
|
+
return (_jsxs("form", { className: "auth-form", onSubmit: handleSubmit, children: [_jsxs("div", { className: "auth-form-header", children: [_jsx("h2", { className: "auth-form-title", children: token ? 'Set new password' : 'Reset your password' }), _jsx("p", { className: "auth-form-subtitle", children: token
|
|
35
|
+
? 'Enter your new password below.'
|
|
36
|
+
: "Enter your email address and we'll send you instructions to reset your password." })] }), (error || passwordError) && (_jsxs("div", { className: "auth-error", role: "alert", children: [_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: _jsx("path", { d: "M8 0C3.58 0 0 3.58 0 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm1 13H7v-2h2v2zm0-3H7V4h2v6z" }) }), error || passwordError] })), token ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "auth-form-group", children: [_jsx("label", { htmlFor: "password", className: "auth-label", children: "New Password" }), _jsx("input", { type: "password", id: "password", className: "auth-input", value: password, onChange: (e) => setPassword(e.target.value), required: true, disabled: loading, placeholder: "Enter new password", autoComplete: "new-password", minLength: 6 })] }), _jsxs("div", { className: "auth-form-group", children: [_jsx("label", { htmlFor: "confirmPassword", className: "auth-label", children: "Confirm Password" }), _jsx("input", { type: "password", id: "confirmPassword", className: "auth-input", value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), required: true, disabled: loading, placeholder: "Confirm new password", autoComplete: "new-password", minLength: 6 })] })] })) : (_jsxs("div", { className: "auth-form-group", children: [_jsx("label", { htmlFor: "email", className: "auth-label", children: "Email address" }), _jsx("input", { type: "email", id: "email", className: "auth-input", value: email, onChange: (e) => setEmail(e.target.value), required: true, disabled: loading, placeholder: "you@example.com", autoComplete: "email" })] })), _jsx("button", { type: "submit", className: "auth-button auth-button-primary", disabled: loading, children: loading ? (_jsx("span", { className: "auth-spinner" })) : token ? ('Reset password') : ('Send reset instructions') }), _jsx("div", { className: "auth-divider", children: _jsx("button", { type: "button", className: "auth-link auth-link-bold", onClick: onBack, disabled: loading, children: "\u2190 Back to Sign in" }) })] }));
|
|
37
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import './AuthForm.css';
|
|
3
|
+
interface PhoneAuthFormProps {
|
|
4
|
+
onSubmit: (phoneNumber: string, verificationCode?: string) => Promise<void>;
|
|
5
|
+
onBack: () => void;
|
|
6
|
+
loading: boolean;
|
|
7
|
+
error?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const PhoneAuthForm: React.FC<PhoneAuthFormProps>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=PhoneAuthForm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhoneAuthForm.d.ts","sourceRoot":"","sources":["../../src/components/PhoneAuthForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AACxC,OAAO,gBAAgB,CAAC;AAExB,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAuGtD,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import './AuthForm.css';
|
|
4
|
+
export const PhoneAuthForm = ({ onSubmit, onBack, loading, error, }) => {
|
|
5
|
+
const [phoneNumber, setPhoneNumber] = useState('');
|
|
6
|
+
const [verificationCode, setVerificationCode] = useState('');
|
|
7
|
+
const [codeSent, setCodeSent] = useState(false);
|
|
8
|
+
const handleSendCode = async (e) => {
|
|
9
|
+
e.preventDefault();
|
|
10
|
+
await onSubmit(phoneNumber);
|
|
11
|
+
setCodeSent(true);
|
|
12
|
+
};
|
|
13
|
+
const handleVerifyCode = async (e) => {
|
|
14
|
+
e.preventDefault();
|
|
15
|
+
await onSubmit(phoneNumber, verificationCode);
|
|
16
|
+
};
|
|
17
|
+
return (_jsxs("form", { className: "auth-form", onSubmit: codeSent ? handleVerifyCode : handleSendCode, children: [_jsxs("div", { className: "auth-form-header", children: [_jsx("h2", { className: "auth-form-title", children: "Phone Authentication" }), _jsx("p", { className: "auth-form-subtitle", children: codeSent
|
|
18
|
+
? 'Enter the verification code sent to your phone.'
|
|
19
|
+
: 'Enter your phone number to receive a verification code.' })] }), error && (_jsxs("div", { className: "auth-error", role: "alert", children: [_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: _jsx("path", { d: "M8 0C3.58 0 0 3.58 0 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm1 13H7v-2h2v2zm0-3H7V4h2v6z" }) }), error] })), !codeSent ? (_jsxs("div", { className: "auth-form-group", children: [_jsx("label", { htmlFor: "phoneNumber", className: "auth-label", children: "Phone Number" }), _jsx("input", { type: "tel", id: "phoneNumber", className: "auth-input", value: phoneNumber, onChange: (e) => setPhoneNumber(e.target.value), required: true, disabled: loading, placeholder: "+1 (555) 123-4567" })] })) : (_jsxs("div", { className: "auth-form-group", children: [_jsx("label", { htmlFor: "verificationCode", className: "auth-label", children: "Verification Code" }), _jsx("input", { type: "text", id: "verificationCode", className: "auth-input", value: verificationCode, onChange: (e) => setVerificationCode(e.target.value), required: true, disabled: loading, placeholder: "123456", maxLength: 6, pattern: "[0-9]{6}" })] })), _jsx("button", { type: "submit", className: "auth-button auth-button-primary", disabled: loading, children: loading ? (_jsx("span", { className: "auth-spinner" })) : codeSent ? ('Verify Code') : ('Send Code') }), _jsx("div", { className: "auth-divider", children: _jsx("button", { type: "button", className: "auth-link auth-link-bold", onClick: onBack, disabled: loading, children: "\u2190 Back to login" }) })] }));
|
|
20
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface ProtectedRouteProps {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
fallback?: React.ReactNode;
|
|
5
|
+
redirectTo?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const ProtectedRoute: React.FC<ProtectedRouteProps>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=ProtectedRoute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProtectedRoute.d.ts","sourceRoot":"","sources":["../../src/components/ProtectedRoute.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAwBxD,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useAuth } from '../context/AuthContext';
|
|
4
|
+
export const ProtectedRoute = ({ children, fallback, redirectTo, }) => {
|
|
5
|
+
const { isAuthenticated, isLoading } = useAuth();
|
|
6
|
+
// Show loading state
|
|
7
|
+
if (isLoading) {
|
|
8
|
+
return _jsx("div", { children: "Loading..." });
|
|
9
|
+
}
|
|
10
|
+
// If not authenticated, redirect or show fallback
|
|
11
|
+
if (!isAuthenticated) {
|
|
12
|
+
if (redirectTo) {
|
|
13
|
+
window.location.href = redirectTo;
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return fallback ? _jsx(_Fragment, { children: fallback }) : _jsx("div", { children: "Access denied. Please log in." });
|
|
17
|
+
}
|
|
18
|
+
// Render protected content
|
|
19
|
+
return _jsx(_Fragment, { children: children });
|
|
20
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AuthProvider } from '../types';
|
|
3
|
+
import './AuthForm.css';
|
|
4
|
+
interface ProviderButtonsProps {
|
|
5
|
+
enabledProviders: AuthProvider[];
|
|
6
|
+
onGoogleLogin: () => Promise<void>;
|
|
7
|
+
onPhoneLogin: () => void;
|
|
8
|
+
loading: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare const ProviderButtons: React.FC<ProviderButtonsProps>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=ProviderButtons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProviderButtons.d.ts","sourceRoot":"","sources":["../../src/components/ProviderButtons.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,gBAAgB,CAAC;AAExB,UAAU,oBAAoB;IAC5B,gBAAgB,EAAE,YAAY,EAAE,CAAC;IACjC,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAuE1D,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import './AuthForm.css';
|
|
4
|
+
export const ProviderButtons = ({ enabledProviders, onGoogleLogin, onPhoneLogin, loading, }) => {
|
|
5
|
+
if (enabledProviders.length === 0)
|
|
6
|
+
return null;
|
|
7
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "auth-or-divider", children: _jsx("span", { children: "or continue with" }) }), _jsxs("div", { className: "auth-provider-buttons", children: [enabledProviders.includes('google') && (_jsxs("button", { type: "button", className: "auth-provider-button", onClick: onGoogleLogin, disabled: loading, children: [_jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [_jsx("path", { d: "M19.6 10.227c0-.709-.064-1.39-.182-2.045H10v3.868h5.382a4.6 4.6 0 01-1.996 3.018v2.51h3.232c1.891-1.742 2.982-4.305 2.982-7.35z", fill: "#4285F4" }), _jsx("path", { d: "M10 20c2.7 0 4.964-.895 6.618-2.423l-3.232-2.509c-.895.6-2.04.955-3.386.955-2.605 0-4.81-1.76-5.595-4.123H1.064v2.59A9.996 9.996 0 0010 20z", fill: "#34A853" }), _jsx("path", { d: "M4.405 11.9c-.2-.6-.314-1.24-.314-1.9 0-.66.114-1.3.314-1.9V5.51H1.064A9.996 9.996 0 000 10c0 1.614.386 3.14 1.064 4.49l3.34-2.59z", fill: "#FBBC05" }), _jsx("path", { d: "M10 3.977c1.468 0 2.786.505 3.823 1.496l2.868-2.868C14.959.99 12.695 0 10 0 6.09 0 2.71 2.24 1.064 5.51l3.34 2.59C5.19 5.736 7.395 3.977 10 3.977z", fill: "#EA4335" })] }), "Continue with Google"] })), enabledProviders.includes('phone') && (_jsxs("button", { type: "button", className: "auth-provider-button", onClick: onPhoneLogin, disabled: loading, children: [_jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V15a2 2 0 01-2 2h-1C7.82 17 2 11.18 2 5V4z" }) }), "Continue with Phone"] }))] })] }));
|
|
8
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { AuthUser } from '../types';
|
|
3
|
+
interface AuthContextValue {
|
|
4
|
+
user: AuthUser | null;
|
|
5
|
+
token: string | null;
|
|
6
|
+
accountData: Record<string, any> | null;
|
|
7
|
+
isAuthenticated: boolean;
|
|
8
|
+
isLoading: boolean;
|
|
9
|
+
login: (token: string, user: AuthUser, accountData?: Record<string, any>) => void;
|
|
10
|
+
logout: () => Promise<void>;
|
|
11
|
+
getToken: () => string | null;
|
|
12
|
+
refreshToken: () => Promise<string>;
|
|
13
|
+
}
|
|
14
|
+
interface AuthProviderProps {
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
}
|
|
17
|
+
export declare const AuthProvider: React.FC<AuthProviderProps>;
|
|
18
|
+
export declare const useAuth: () => AuthContextValue;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=AuthContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../../src/context/AuthContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsE,MAAM,OAAO,CAAC;AAG3F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,UAAU,gBAAgB;IACxB,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;IAClF,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,QAAQ,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACrC;AAID,UAAU,iBAAiB;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA4EpD,CAAC;AAEF,eAAO,MAAM,OAAO,QAAO,gBAM1B,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';
|
|
3
|
+
import { tokenStorage } from '../utils/tokenStorage';
|
|
4
|
+
import { createSmartlinksClient } from '../smartlinks';
|
|
5
|
+
const AuthContext = createContext(undefined);
|
|
6
|
+
export const AuthProvider = ({ children, apiEndpoint, clientId }) => {
|
|
7
|
+
const [user, setUser] = useState(null);
|
|
8
|
+
const [token, setToken] = useState(null);
|
|
9
|
+
const [accountData, setAccountData] = useState(null);
|
|
10
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
11
|
+
const [smartlinks, setSmartlinks] = useState(null);
|
|
12
|
+
// Initialize Smartlinks SDK
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const client = createSmartlinksClient({
|
|
15
|
+
apiEndpoint,
|
|
16
|
+
clientId,
|
|
17
|
+
});
|
|
18
|
+
setSmartlinks(client);
|
|
19
|
+
}, [apiEndpoint, clientId]);
|
|
20
|
+
// Initialize auth state from localStorage
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const storedToken = tokenStorage.getToken();
|
|
23
|
+
const storedUser = tokenStorage.getUser();
|
|
24
|
+
const storedAccountData = tokenStorage.getAccountData();
|
|
25
|
+
if (storedToken && storedUser) {
|
|
26
|
+
setToken(storedToken.token);
|
|
27
|
+
setUser(storedUser);
|
|
28
|
+
setAccountData(storedAccountData);
|
|
29
|
+
// Set token in Smartlinks SDK
|
|
30
|
+
if (smartlinks) {
|
|
31
|
+
smartlinks.setToken(storedToken.token);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
setIsLoading(false);
|
|
35
|
+
}, [smartlinks]);
|
|
36
|
+
const login = useCallback((authToken, authUser, authAccountData) => {
|
|
37
|
+
// Store token, user, and account data
|
|
38
|
+
tokenStorage.saveToken(authToken);
|
|
39
|
+
tokenStorage.saveUser(authUser);
|
|
40
|
+
if (authAccountData) {
|
|
41
|
+
tokenStorage.saveAccountData(authAccountData);
|
|
42
|
+
}
|
|
43
|
+
setToken(authToken);
|
|
44
|
+
setUser(authUser);
|
|
45
|
+
setAccountData(authAccountData || null);
|
|
46
|
+
// Set token in Smartlinks SDK
|
|
47
|
+
if (smartlinks) {
|
|
48
|
+
smartlinks.setToken(authToken);
|
|
49
|
+
}
|
|
50
|
+
}, [smartlinks]);
|
|
51
|
+
const logout = useCallback(async () => {
|
|
52
|
+
// Logout via Smartlinks SDK if available
|
|
53
|
+
if (smartlinks) {
|
|
54
|
+
try {
|
|
55
|
+
await smartlinks.logout();
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.error('Smartlinks logout error:', error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Clear local storage
|
|
62
|
+
tokenStorage.clearAll();
|
|
63
|
+
setToken(null);
|
|
64
|
+
setUser(null);
|
|
65
|
+
setAccountData(null);
|
|
66
|
+
// Clear token from Smartlinks SDK
|
|
67
|
+
if (smartlinks) {
|
|
68
|
+
smartlinks.clearToken();
|
|
69
|
+
}
|
|
70
|
+
}, [smartlinks]);
|
|
71
|
+
const getToken = useCallback(() => {
|
|
72
|
+
const storedToken = tokenStorage.getToken();
|
|
73
|
+
return storedToken ? storedToken.token : null;
|
|
74
|
+
}, []);
|
|
75
|
+
const refreshToken = useCallback(async () => {
|
|
76
|
+
if (!smartlinks) {
|
|
77
|
+
throw new Error('Smartlinks SDK not initialized');
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const newToken = await smartlinks.refreshToken();
|
|
81
|
+
// Update stored token
|
|
82
|
+
tokenStorage.saveToken(newToken);
|
|
83
|
+
setToken(newToken);
|
|
84
|
+
return newToken;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
console.error('Token refresh failed:', error);
|
|
88
|
+
// If refresh fails, logout user
|
|
89
|
+
await logout();
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}, [smartlinks, logout]);
|
|
93
|
+
const value = {
|
|
94
|
+
user,
|
|
95
|
+
token,
|
|
96
|
+
accountData,
|
|
97
|
+
isAuthenticated: !!token && !!user,
|
|
98
|
+
isLoading,
|
|
99
|
+
smartlinks,
|
|
100
|
+
login,
|
|
101
|
+
logout,
|
|
102
|
+
getToken,
|
|
103
|
+
refreshToken,
|
|
104
|
+
};
|
|
105
|
+
return _jsx(AuthContext.Provider, { value: value, children: children });
|
|
106
|
+
};
|
|
107
|
+
export const useAuth = () => {
|
|
108
|
+
const context = useContext(AuthContext);
|
|
109
|
+
if (context === undefined) {
|
|
110
|
+
throw new Error('useAuth must be used within an AuthProvider');
|
|
111
|
+
}
|
|
112
|
+
return context;
|
|
113
|
+
};
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
.auth-container{align-items:center;background:linear-gradient(135deg,var(--auth-bg-color,#e0f2fe) 0,#f0f9ff 100%);display:flex;font-family:var(--auth-font-family,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif);justify-content:center;min-height:100vh;padding:1rem}.auth-theme-dark.auth-container{background:linear-gradient(135deg,#0f172a,#1e293b)}.auth-card{animation:slideUp .4s cubic-bezier(.16,1,.3,1);background:#fff;border-radius:16px;box-shadow:0 10px 40px rgba(59,130,246,.1);max-width:440px;padding:2.5rem;width:100%}.auth-theme-dark .auth-card{background:#1e293b;box-shadow:0 10px 40px rgba(0,0,0,.3)}@keyframes slideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.auth-header{margin-bottom:2rem;text-align:center}.auth-logo{animation:float 3s ease-in-out infinite;display:inline-flex;margin-bottom:1rem}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-8px)}}.auth-title{color:#1e293b;font-size:1.75rem;font-weight:700;margin:0}.auth-subtitle{color:#64748b;font-size:.875rem;margin:.25rem 0 0}.auth-theme-dark .auth-title{color:#f1f5f9}.auth-theme-dark .auth-subtitle{color:#94a3b8}.auth-footer{align-items:center;border-top:1px solid #e2e8f0;display:flex;font-size:.875rem;gap:.75rem;justify-content:center;margin-top:1rem;padding-top:1rem}.auth-theme-dark .auth-footer{border-top-color:#334155}.auth-footer a{color:var(--auth-primary-color,#3b82f6);text-decoration:none}.auth-footer a:hover{text-decoration:underline}.auth-footer span{color:#cbd5e1}.auth-theme-dark .auth-footer span{color:#475569}.auth-spinner{border:3px solid #e2e8f0;border-top:3px solid var(--auth-primary-color,#3b82f6);height:40px;margin:0 auto;width:40px}@media (max-width:640px){.auth-card{padding:2rem 1.5rem}.auth-title{font-size:1.5rem}}.auth-form{width:100%}.auth-form-header{margin-bottom:1.5rem}.auth-form-title{color:#1e293b;font-size:1.5rem;font-weight:700;margin:0 0 .5rem}.auth-theme-dark .auth-form-title{color:#f1f5f9}.auth-form-subtitle{color:#64748b;font-size:.875rem;margin:0}.auth-theme-dark .auth-form-subtitle{color:#94a3b8}.auth-error{align-items:center;animation:shake .4s ease;background:#fef2f2;border:1px solid #fecaca;border-radius:.5rem;color:#dc2626;display:flex;font-size:.875rem;gap:.5rem;margin-bottom:1rem;padding:.75rem 1rem}.auth-theme-dark .auth-error{background:#7f1d1d;border-color:#991b1b;color:#fca5a5}@keyframes shake{0%,to{transform:translateX(0)}25%{transform:translateX(-8px)}75%{transform:translateX(8px)}}.auth-form-group{margin-bottom:1rem}.auth-label{color:#334155;display:block;font-size:.875rem;font-weight:500;margin-bottom:.5rem}.auth-theme-dark .auth-label{color:#cbd5e1}.auth-input{background:#f8fafc;border:1px solid #e2e8f0;border-radius:.5rem;box-sizing:border-box;color:#1e293b;font-size:1rem;padding:.75rem 1rem;transition:all .2s ease;width:100%}.auth-input:focus{background:#fff;border-color:#3b82f6;box-shadow:0 0 0 3px rgba(59,130,246,.1);outline:none}.auth-input:disabled{cursor:not-allowed;opacity:.6}.auth-theme-dark .auth-input{background:#0f172a;border-color:#334155;color:#f1f5f9}.auth-theme-dark .auth-input:focus{background:#1e293b;border-color:#3b82f6}.auth-form-footer{display:flex;justify-content:flex-end;margin-bottom:1.5rem}.auth-link{background:none;border:none;color:#3b82f6;cursor:pointer;font-size:.875rem;padding:0;transition:color .2s ease}.auth-link:hover:not(:disabled){color:#1d4ed8;text-decoration:underline}.auth-link:disabled{cursor:not-allowed;opacity:.6}.auth-button,.auth-link-bold{font-weight:600}.auth-button{align-items:center;border:none;border-radius:.5rem;cursor:pointer;display:flex;font-size:1rem;gap:.5rem;justify-content:center;padding:.875rem 1.5rem;transition:all .2s ease;width:100%}.auth-button:disabled{cursor:not-allowed;opacity:.6}.auth-button-primary{background:linear-gradient(135deg,#3b82f6,#1d4ed8);box-shadow:0 4px 12px rgba(59,130,246,.25);color:#fff}.auth-button-primary:hover:not(:disabled){box-shadow:0 6px 20px rgba(59,130,246,.35);transform:translateY(-2px)}.auth-button-primary:active:not(:disabled){transform:translateY(0)}.auth-button-secondary{background:#fff;border:1px solid #e2e8f0;box-shadow:0 1px 3px rgba(0,0,0,.05);color:#334155}.auth-button-secondary:hover:not(:disabled){background:#f8fafc;border-color:#cbd5e1}.auth-theme-dark .auth-button-secondary{background:#0f172a;border-color:#334155;color:#f1f5f9}.auth-theme-dark .auth-button-secondary:hover:not(:disabled){background:#1e293b;border-color:#475569}.auth-spinner{animation:spin .8s linear infinite;border:2px solid hsla(0,0%,100%,.3);border-radius:50%;border-top-color:#fff;display:inline-block;height:18px;width:18px}@keyframes spin{to{transform:rotate(1turn)}}.auth-divider{align-items:center;color:#64748b;display:flex;font-size:.875rem;gap:.5rem;justify-content:center;margin-top:1.5rem}.auth-theme-dark .auth-divider{color:#94a3b8}.auth-provider-buttons{display:flex;flex-direction:column;gap:.75rem;margin-top:1.5rem}.auth-provider-button{align-items:center;background:#fff;border:1px solid #e2e8f0;border-radius:.5rem;color:#334155;cursor:pointer;display:flex;font-size:.9375rem;font-weight:500;gap:.75rem;justify-content:center;padding:.875rem 1.5rem;transition:all .2s ease;width:100%}.auth-provider-button:hover:not(:disabled){background:#f8fafc;border-color:#cbd5e1;box-shadow:0 4px 12px rgba(0,0,0,.08);transform:translateY(-1px)}.auth-provider-button:disabled{cursor:not-allowed;opacity:.6}.auth-theme-dark .auth-provider-button{background:#0f172a;border-color:#334155;color:#f1f5f9}.auth-theme-dark .auth-provider-button:hover:not(:disabled){background:#1e293b;border-color:#475569}.auth-or-divider{align-items:center;color:#94a3b8;display:flex;font-size:.875rem;margin:1.5rem 0;text-align:center}.auth-or-divider:after,.auth-or-divider:before{border-bottom:1px solid #e2e8f0;content:"";flex:1}.auth-or-divider span{padding:0 1rem}.auth-theme-dark .auth-or-divider:after,.auth-theme-dark .auth-or-divider:before{border-color:#334155}@media (max-width:640px){.auth-form-title{font-size:1.25rem}.auth-button,.auth-provider-button{font-size:.9375rem;padding:.75rem 1rem}}
|
|
2
|
+
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["AuthContainer.css","AuthForm.css"],"names":[],"mappings":"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","file":"index.css","sourcesContent":[".auth-container {\r\n min-height: 100vh;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 1rem;\r\n background: linear-gradient(135deg, var(--auth-bg-color, #e0f2fe) 0%, #f0f9ff 100%);\r\n font-family: var(--auth-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif);\r\n}\r\n\r\n.auth-theme-dark.auth-container {\r\n background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);\r\n}\r\n\r\n.auth-card {\r\n width: 100%;\r\n max-width: 440px;\r\n background: white;\r\n border-radius: 16px;\r\n box-shadow: 0 10px 40px rgba(59, 130, 246, 0.1);\r\n padding: 2.5rem;\r\n animation: slideUp 0.4s cubic-bezier(0.16, 1, 0.3, 1);\r\n}\r\n\r\n.auth-theme-dark .auth-card {\r\n background: #1e293b;\r\n box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n@keyframes slideUp {\r\n from {\r\n opacity: 0;\r\n transform: translateY(20px);\r\n }\r\n to {\r\n opacity: 1;\r\n transform: translateY(0);\r\n }\r\n}\r\n\r\n.auth-header {\r\n text-align: center;\r\n margin-bottom: 2rem;\r\n}\r\n\r\n.auth-logo {\r\n display: inline-flex;\r\n margin-bottom: 1rem;\r\n animation: float 3s ease-in-out infinite;\r\n}\r\n\r\n@keyframes float {\r\n 0%, 100% {\r\n transform: translateY(0);\r\n }\r\n 50% {\r\n transform: translateY(-8px);\r\n }\r\n}\r\n\r\n.auth-title {\r\n font-size: 1.75rem;\r\n font-weight: 700;\r\n color: #1e293b;\r\n margin: 0;\r\n}\r\n\r\n.auth-subtitle {\r\n font-size: 0.875rem;\r\n color: #64748b;\r\n margin: 0.25rem 0 0 0;\r\n}\r\n\r\n.auth-theme-dark .auth-title {\r\n color: #f1f5f9;\r\n}\r\n\r\n.auth-theme-dark .auth-subtitle {\r\n color: #94a3b8;\r\n}\r\n\r\n.auth-content {\r\n /* Content styles handled by child components */\r\n}\r\n\r\n.auth-footer {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 0.75rem;\r\n padding-top: 1rem;\r\n margin-top: 1rem;\r\n border-top: 1px solid #e2e8f0;\r\n font-size: 0.875rem;\r\n}\r\n\r\n.auth-theme-dark .auth-footer {\r\n border-top-color: #334155;\r\n}\r\n\r\n.auth-footer a {\r\n color: var(--auth-primary-color, #3B82F6);\r\n text-decoration: none;\r\n}\r\n\r\n.auth-footer a:hover {\r\n text-decoration: underline;\r\n}\r\n\r\n.auth-footer span {\r\n color: #cbd5e1;\r\n}\r\n\r\n.auth-theme-dark .auth-footer span {\r\n color: #475569;\r\n}\r\n\r\n.auth-spinner {\r\n width: 40px;\r\n height: 40px;\r\n border: 3px solid #e2e8f0;\r\n border-top-color: var(--auth-primary-color, #3B82F6);\r\n border-radius: 50%;\r\n animation: spin 0.8s linear infinite;\r\n margin: 0 auto;\r\n}\r\n\r\n@keyframes spin {\r\n to {\r\n transform: rotate(360deg);\r\n }\r\n}\r\n\r\n@media (max-width: 640px) {\r\n .auth-card {\r\n padding: 2rem 1.5rem;\r\n }\r\n \r\n .auth-title {\r\n font-size: 1.5rem;\r\n }\r\n}\r\n",".auth-form {\r\n width: 100%;\r\n}\r\n\r\n.auth-form-header {\r\n margin-bottom: 1.5rem;\r\n}\r\n\r\n.auth-form-title {\r\n font-size: 1.5rem;\r\n font-weight: 700;\r\n color: #1e293b;\r\n margin: 0 0 0.5rem 0;\r\n}\r\n\r\n.auth-theme-dark .auth-form-title {\r\n color: #f1f5f9;\r\n}\r\n\r\n.auth-form-subtitle {\r\n font-size: 0.875rem;\r\n color: #64748b;\r\n margin: 0;\r\n}\r\n\r\n.auth-theme-dark .auth-form-subtitle {\r\n color: #94a3b8;\r\n}\r\n\r\n.auth-error {\r\n display: flex;\r\n align-items: center;\r\n gap: 0.5rem;\r\n padding: 0.75rem 1rem;\r\n background: #fef2f2;\r\n border: 1px solid #fecaca;\r\n border-radius: 0.5rem;\r\n color: #dc2626;\r\n font-size: 0.875rem;\r\n margin-bottom: 1rem;\r\n animation: shake 0.4s ease;\r\n}\r\n\r\n.auth-theme-dark .auth-error {\r\n background: #7f1d1d;\r\n border-color: #991b1b;\r\n color: #fca5a5;\r\n}\r\n\r\n@keyframes shake {\r\n 0%, 100% { transform: translateX(0); }\r\n 25% { transform: translateX(-8px); }\r\n 75% { transform: translateX(8px); }\r\n}\r\n\r\n.auth-form-group {\r\n margin-bottom: 1rem;\r\n}\r\n\r\n.auth-label {\r\n display: block;\r\n font-size: 0.875rem;\r\n font-weight: 500;\r\n color: #334155;\r\n margin-bottom: 0.5rem;\r\n}\r\n\r\n.auth-theme-dark .auth-label {\r\n color: #cbd5e1;\r\n}\r\n\r\n.auth-input {\r\n width: 100%;\r\n padding: 0.75rem 1rem;\r\n font-size: 1rem;\r\n color: #1e293b;\r\n background: #f8fafc;\r\n border: 1px solid #e2e8f0;\r\n border-radius: 0.5rem;\r\n transition: all 0.2s ease;\r\n box-sizing: border-box;\r\n}\r\n\r\n.auth-input:focus {\r\n outline: none;\r\n border-color: #3b82f6;\r\n background: white;\r\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\r\n}\r\n\r\n.auth-input:disabled {\r\n opacity: 0.6;\r\n cursor: not-allowed;\r\n}\r\n\r\n.auth-theme-dark .auth-input {\r\n background: #0f172a;\r\n border-color: #334155;\r\n color: #f1f5f9;\r\n}\r\n\r\n.auth-theme-dark .auth-input:focus {\r\n background: #1e293b;\r\n border-color: #3b82f6;\r\n}\r\n\r\n.auth-form-footer {\r\n display: flex;\r\n justify-content: flex-end;\r\n margin-bottom: 1.5rem;\r\n}\r\n\r\n.auth-link {\r\n background: none;\r\n border: none;\r\n padding: 0;\r\n font-size: 0.875rem;\r\n color: #3b82f6;\r\n cursor: pointer;\r\n transition: color 0.2s ease;\r\n}\r\n\r\n.auth-link:hover:not(:disabled) {\r\n color: #1d4ed8;\r\n text-decoration: underline;\r\n}\r\n\r\n.auth-link:disabled {\r\n opacity: 0.6;\r\n cursor: not-allowed;\r\n}\r\n\r\n.auth-link-bold {\r\n font-weight: 600;\r\n}\r\n\r\n.auth-button {\r\n width: 100%;\r\n padding: 0.875rem 1.5rem;\r\n font-size: 1rem;\r\n font-weight: 600;\r\n border: none;\r\n border-radius: 0.5rem;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 0.5rem;\r\n}\r\n\r\n.auth-button:disabled {\r\n opacity: 0.6;\r\n cursor: not-allowed;\r\n}\r\n\r\n.auth-button-primary {\r\n background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);\r\n color: white;\r\n box-shadow: 0 4px 12px rgba(59, 130, 246, 0.25);\r\n}\r\n\r\n.auth-button-primary:hover:not(:disabled) {\r\n transform: translateY(-2px);\r\n box-shadow: 0 6px 20px rgba(59, 130, 246, 0.35);\r\n}\r\n\r\n.auth-button-primary:active:not(:disabled) {\r\n transform: translateY(0);\r\n}\r\n\r\n.auth-button-secondary {\r\n background: white;\r\n color: #334155;\r\n border: 1px solid #e2e8f0;\r\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\r\n}\r\n\r\n.auth-button-secondary:hover:not(:disabled) {\r\n background: #f8fafc;\r\n border-color: #cbd5e1;\r\n}\r\n\r\n.auth-theme-dark .auth-button-secondary {\r\n background: #0f172a;\r\n color: #f1f5f9;\r\n border-color: #334155;\r\n}\r\n\r\n.auth-theme-dark .auth-button-secondary:hover:not(:disabled) {\r\n background: #1e293b;\r\n border-color: #475569;\r\n}\r\n\r\n.auth-spinner {\r\n display: inline-block;\r\n width: 18px;\r\n height: 18px;\r\n border: 2px solid rgba(255, 255, 255, 0.3);\r\n border-top-color: white;\r\n border-radius: 50%;\r\n animation: spin 0.8s linear infinite;\r\n}\r\n\r\n@keyframes spin {\r\n to { transform: rotate(360deg); }\r\n}\r\n\r\n.auth-divider {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 0.5rem;\r\n margin-top: 1.5rem;\r\n font-size: 0.875rem;\r\n color: #64748b;\r\n}\r\n\r\n.auth-theme-dark .auth-divider {\r\n color: #94a3b8;\r\n}\r\n\r\n.auth-provider-buttons {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 0.75rem;\r\n margin-top: 1.5rem;\r\n}\r\n\r\n.auth-provider-button {\r\n width: 100%;\r\n padding: 0.875rem 1.5rem;\r\n font-size: 0.9375rem;\r\n font-weight: 500;\r\n background: white;\r\n color: #334155;\r\n border: 1px solid #e2e8f0;\r\n border-radius: 0.5rem;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 0.75rem;\r\n}\r\n\r\n.auth-provider-button:hover:not(:disabled) {\r\n background: #f8fafc;\r\n border-color: #cbd5e1;\r\n transform: translateY(-1px);\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\r\n}\r\n\r\n.auth-provider-button:disabled {\r\n opacity: 0.6;\r\n cursor: not-allowed;\r\n}\r\n\r\n.auth-theme-dark .auth-provider-button {\r\n background: #0f172a;\r\n color: #f1f5f9;\r\n border-color: #334155;\r\n}\r\n\r\n.auth-theme-dark .auth-provider-button:hover:not(:disabled) {\r\n background: #1e293b;\r\n border-color: #475569;\r\n}\r\n\r\n.auth-or-divider {\r\n display: flex;\r\n align-items: center;\r\n text-align: center;\r\n margin: 1.5rem 0;\r\n color: #94a3b8;\r\n font-size: 0.875rem;\r\n}\r\n\r\n.auth-or-divider::before,\r\n.auth-or-divider::after {\r\n content: '';\r\n flex: 1;\r\n border-bottom: 1px solid #e2e8f0;\r\n}\r\n\r\n.auth-or-divider span {\r\n padding: 0 1rem;\r\n}\r\n\r\n.auth-theme-dark .auth-or-divider::before,\r\n.auth-theme-dark .auth-or-divider::after {\r\n border-color: #334155;\r\n}\r\n\r\n@media (max-width: 640px) {\r\n .auth-form-title {\r\n font-size: 1.25rem;\r\n }\r\n \r\n .auth-button,\r\n .auth-provider-button {\r\n padding: 0.75rem 1rem;\r\n font-size: 0.9375rem;\r\n }\r\n}\r\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { SmartlinksAuthUIProps } from './types';
|
|
3
|
+
export declare const SmartlinksAuthUI: React.FC<SmartlinksAuthUIProps>;
|
|
4
|
+
export { AuthProvider, useAuth } from './context/AuthContext';
|
|
5
|
+
export { ProtectedRoute } from './components/ProtectedRoute';
|
|
6
|
+
export { tokenStorage } from './utils/tokenStorage';
|
|
7
|
+
export { AuthUIPreview } from './components/AuthUIPreview';
|
|
8
|
+
export type * from './types';
|
|
9
|
+
export { SmartlinksAuthUI as FirebaseAuthUI };
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAQnD,OAAO,KAAK,EAAE,qBAAqB,EAAyC,MAAM,SAAS,CAAC;AAE5F,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAwnB5D,CAAC;AAGF,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D,mBAAmB,SAAS,CAAC;AAG7B,OAAO,EAAE,gBAAgB,IAAI,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
.auth-container{align-items:center;background:linear-gradient(135deg,var(--auth-bg-color,#e0f2fe) 0,#f0f9ff 100%);display:flex;font-family:var(--auth-font-family,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif);justify-content:center;min-height:100vh;padding:1rem}.auth-theme-dark.auth-container{background:linear-gradient(135deg,#0f172a,#1e293b)}.auth-card{animation:slideUp .4s cubic-bezier(.16,1,.3,1);background:#fff;border-radius:16px;box-shadow:0 10px 40px rgba(59,130,246,.1);max-width:440px;padding:2.5rem;width:100%}.auth-theme-dark .auth-card{background:#1e293b;box-shadow:0 10px 40px rgba(0,0,0,.3)}@keyframes slideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.auth-header{margin-bottom:2rem;text-align:center}.auth-logo{animation:float 3s ease-in-out infinite;display:inline-flex;margin-bottom:1rem}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-8px)}}.auth-title{color:#1e293b;font-size:1.75rem;font-weight:700;margin:0}.auth-subtitle{color:#64748b;font-size:.875rem;margin:.25rem 0 0}.auth-theme-dark .auth-title{color:#f1f5f9}.auth-theme-dark .auth-subtitle{color:#94a3b8}.auth-footer{align-items:center;border-top:1px solid #e2e8f0;display:flex;font-size:.875rem;gap:.75rem;justify-content:center;margin-top:1rem;padding-top:1rem}.auth-theme-dark .auth-footer{border-top-color:#334155}.auth-footer a{color:var(--auth-primary-color,#3b82f6);text-decoration:none}.auth-footer a:hover{text-decoration:underline}.auth-footer span{color:#cbd5e1}.auth-theme-dark .auth-footer span{color:#475569}.auth-spinner{border:3px solid #e2e8f0;border-top:3px solid var(--auth-primary-color,#3b82f6);height:40px;margin:0 auto;width:40px}@media (max-width:640px){.auth-card{padding:2rem 1.5rem}.auth-title{font-size:1.5rem}}.auth-form{width:100%}.auth-form-header{margin-bottom:1.5rem}.auth-form-title{color:#1e293b;font-size:1.5rem;font-weight:700;margin:0 0 .5rem}.auth-theme-dark .auth-form-title{color:#f1f5f9}.auth-form-subtitle{color:#64748b;font-size:.875rem;margin:0}.auth-theme-dark .auth-form-subtitle{color:#94a3b8}.auth-error{align-items:center;animation:shake .4s ease;background:#fef2f2;border:1px solid #fecaca;border-radius:.5rem;color:#dc2626;display:flex;font-size:.875rem;gap:.5rem;margin-bottom:1rem;padding:.75rem 1rem}.auth-theme-dark .auth-error{background:#7f1d1d;border-color:#991b1b;color:#fca5a5}@keyframes shake{0%,to{transform:translateX(0)}25%{transform:translateX(-8px)}75%{transform:translateX(8px)}}.auth-form-group{margin-bottom:1rem}.auth-label{color:#334155;display:block;font-size:.875rem;font-weight:500;margin-bottom:.5rem}.auth-theme-dark .auth-label{color:#cbd5e1}.auth-input{background:#f8fafc;border:1px solid #e2e8f0;border-radius:.5rem;box-sizing:border-box;color:#1e293b;font-size:1rem;padding:.75rem 1rem;transition:all .2s ease;width:100%}.auth-input:focus{background:#fff;border-color:#3b82f6;box-shadow:0 0 0 3px rgba(59,130,246,.1);outline:none}.auth-input:disabled{cursor:not-allowed;opacity:.6}.auth-theme-dark .auth-input{background:#0f172a;border-color:#334155;color:#f1f5f9}.auth-theme-dark .auth-input:focus{background:#1e293b;border-color:#3b82f6}.auth-form-footer{display:flex;justify-content:flex-end;margin-bottom:1.5rem}.auth-link{background:none;border:none;color:#3b82f6;cursor:pointer;font-size:.875rem;padding:0;transition:color .2s ease}.auth-link:hover:not(:disabled){color:#1d4ed8;text-decoration:underline}.auth-link:disabled{cursor:not-allowed;opacity:.6}.auth-button,.auth-link-bold{font-weight:600}.auth-button{align-items:center;border:none;border-radius:.5rem;cursor:pointer;display:flex;font-size:1rem;gap:.5rem;justify-content:center;padding:.875rem 1.5rem;transition:all .2s ease;width:100%}.auth-button:disabled{cursor:not-allowed;opacity:.6}.auth-button-primary{background:linear-gradient(135deg,#3b82f6,#1d4ed8);box-shadow:0 4px 12px rgba(59,130,246,.25);color:#fff}.auth-button-primary:hover:not(:disabled){box-shadow:0 6px 20px rgba(59,130,246,.35);transform:translateY(-2px)}.auth-button-primary:active:not(:disabled){transform:translateY(0)}.auth-button-secondary{background:#fff;border:1px solid #e2e8f0;box-shadow:0 1px 3px rgba(0,0,0,.05);color:#334155}.auth-button-secondary:hover:not(:disabled){background:#f8fafc;border-color:#cbd5e1}.auth-theme-dark .auth-button-secondary{background:#0f172a;border-color:#334155;color:#f1f5f9}.auth-theme-dark .auth-button-secondary:hover:not(:disabled){background:#1e293b;border-color:#475569}.auth-spinner{animation:spin .8s linear infinite;border:2px solid hsla(0,0%,100%,.3);border-radius:50%;border-top-color:#fff;display:inline-block;height:18px;width:18px}@keyframes spin{to{transform:rotate(1turn)}}.auth-divider{align-items:center;color:#64748b;display:flex;font-size:.875rem;gap:.5rem;justify-content:center;margin-top:1.5rem}.auth-theme-dark .auth-divider{color:#94a3b8}.auth-provider-buttons{display:flex;flex-direction:column;gap:.75rem;margin-top:1.5rem}.auth-provider-button{align-items:center;background:#fff;border:1px solid #e2e8f0;border-radius:.5rem;color:#334155;cursor:pointer;display:flex;font-size:.9375rem;font-weight:500;gap:.75rem;justify-content:center;padding:.875rem 1.5rem;transition:all .2s ease;width:100%}.auth-provider-button:hover:not(:disabled){background:#f8fafc;border-color:#cbd5e1;box-shadow:0 4px 12px rgba(0,0,0,.08);transform:translateY(-1px)}.auth-provider-button:disabled{cursor:not-allowed;opacity:.6}.auth-theme-dark .auth-provider-button{background:#0f172a;border-color:#334155;color:#f1f5f9}.auth-theme-dark .auth-provider-button:hover:not(:disabled){background:#1e293b;border-color:#475569}.auth-or-divider{align-items:center;color:#94a3b8;display:flex;font-size:.875rem;margin:1.5rem 0;text-align:center}.auth-or-divider:after,.auth-or-divider:before{border-bottom:1px solid #e2e8f0;content:"";flex:1}.auth-or-divider span{padding:0 1rem}.auth-theme-dark .auth-or-divider:after,.auth-theme-dark .auth-or-divider:before{border-color:#334155}@media (max-width:640px){.auth-form-title{font-size:1.25rem}.auth-button,.auth-provider-button{font-size:.9375rem;padding:.75rem 1rem}}
|
|
2
|
+
/*# sourceMappingURL=index.esm.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["AuthContainer.css","AuthForm.css"],"names":[],"mappings":"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","file":"index.esm.css","sourcesContent":[".auth-container {\r\n min-height: 100vh;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 1rem;\r\n background: linear-gradient(135deg, var(--auth-bg-color, #e0f2fe) 0%, #f0f9ff 100%);\r\n font-family: var(--auth-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif);\r\n}\r\n\r\n.auth-theme-dark.auth-container {\r\n background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);\r\n}\r\n\r\n.auth-card {\r\n width: 100%;\r\n max-width: 440px;\r\n background: white;\r\n border-radius: 16px;\r\n box-shadow: 0 10px 40px rgba(59, 130, 246, 0.1);\r\n padding: 2.5rem;\r\n animation: slideUp 0.4s cubic-bezier(0.16, 1, 0.3, 1);\r\n}\r\n\r\n.auth-theme-dark .auth-card {\r\n background: #1e293b;\r\n box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n@keyframes slideUp {\r\n from {\r\n opacity: 0;\r\n transform: translateY(20px);\r\n }\r\n to {\r\n opacity: 1;\r\n transform: translateY(0);\r\n }\r\n}\r\n\r\n.auth-header {\r\n text-align: center;\r\n margin-bottom: 2rem;\r\n}\r\n\r\n.auth-logo {\r\n display: inline-flex;\r\n margin-bottom: 1rem;\r\n animation: float 3s ease-in-out infinite;\r\n}\r\n\r\n@keyframes float {\r\n 0%, 100% {\r\n transform: translateY(0);\r\n }\r\n 50% {\r\n transform: translateY(-8px);\r\n }\r\n}\r\n\r\n.auth-title {\r\n font-size: 1.75rem;\r\n font-weight: 700;\r\n color: #1e293b;\r\n margin: 0;\r\n}\r\n\r\n.auth-subtitle {\r\n font-size: 0.875rem;\r\n color: #64748b;\r\n margin: 0.25rem 0 0 0;\r\n}\r\n\r\n.auth-theme-dark .auth-title {\r\n color: #f1f5f9;\r\n}\r\n\r\n.auth-theme-dark .auth-subtitle {\r\n color: #94a3b8;\r\n}\r\n\r\n.auth-content {\r\n /* Content styles handled by child components */\r\n}\r\n\r\n.auth-footer {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 0.75rem;\r\n padding-top: 1rem;\r\n margin-top: 1rem;\r\n border-top: 1px solid #e2e8f0;\r\n font-size: 0.875rem;\r\n}\r\n\r\n.auth-theme-dark .auth-footer {\r\n border-top-color: #334155;\r\n}\r\n\r\n.auth-footer a {\r\n color: var(--auth-primary-color, #3B82F6);\r\n text-decoration: none;\r\n}\r\n\r\n.auth-footer a:hover {\r\n text-decoration: underline;\r\n}\r\n\r\n.auth-footer span {\r\n color: #cbd5e1;\r\n}\r\n\r\n.auth-theme-dark .auth-footer span {\r\n color: #475569;\r\n}\r\n\r\n.auth-spinner {\r\n width: 40px;\r\n height: 40px;\r\n border: 3px solid #e2e8f0;\r\n border-top-color: var(--auth-primary-color, #3B82F6);\r\n border-radius: 50%;\r\n animation: spin 0.8s linear infinite;\r\n margin: 0 auto;\r\n}\r\n\r\n@keyframes spin {\r\n to {\r\n transform: rotate(360deg);\r\n }\r\n}\r\n\r\n@media (max-width: 640px) {\r\n .auth-card {\r\n padding: 2rem 1.5rem;\r\n }\r\n \r\n .auth-title {\r\n font-size: 1.5rem;\r\n }\r\n}\r\n",".auth-form {\r\n width: 100%;\r\n}\r\n\r\n.auth-form-header {\r\n margin-bottom: 1.5rem;\r\n}\r\n\r\n.auth-form-title {\r\n font-size: 1.5rem;\r\n font-weight: 700;\r\n color: #1e293b;\r\n margin: 0 0 0.5rem 0;\r\n}\r\n\r\n.auth-theme-dark .auth-form-title {\r\n color: #f1f5f9;\r\n}\r\n\r\n.auth-form-subtitle {\r\n font-size: 0.875rem;\r\n color: #64748b;\r\n margin: 0;\r\n}\r\n\r\n.auth-theme-dark .auth-form-subtitle {\r\n color: #94a3b8;\r\n}\r\n\r\n.auth-error {\r\n display: flex;\r\n align-items: center;\r\n gap: 0.5rem;\r\n padding: 0.75rem 1rem;\r\n background: #fef2f2;\r\n border: 1px solid #fecaca;\r\n border-radius: 0.5rem;\r\n color: #dc2626;\r\n font-size: 0.875rem;\r\n margin-bottom: 1rem;\r\n animation: shake 0.4s ease;\r\n}\r\n\r\n.auth-theme-dark .auth-error {\r\n background: #7f1d1d;\r\n border-color: #991b1b;\r\n color: #fca5a5;\r\n}\r\n\r\n@keyframes shake {\r\n 0%, 100% { transform: translateX(0); }\r\n 25% { transform: translateX(-8px); }\r\n 75% { transform: translateX(8px); }\r\n}\r\n\r\n.auth-form-group {\r\n margin-bottom: 1rem;\r\n}\r\n\r\n.auth-label {\r\n display: block;\r\n font-size: 0.875rem;\r\n font-weight: 500;\r\n color: #334155;\r\n margin-bottom: 0.5rem;\r\n}\r\n\r\n.auth-theme-dark .auth-label {\r\n color: #cbd5e1;\r\n}\r\n\r\n.auth-input {\r\n width: 100%;\r\n padding: 0.75rem 1rem;\r\n font-size: 1rem;\r\n color: #1e293b;\r\n background: #f8fafc;\r\n border: 1px solid #e2e8f0;\r\n border-radius: 0.5rem;\r\n transition: all 0.2s ease;\r\n box-sizing: border-box;\r\n}\r\n\r\n.auth-input:focus {\r\n outline: none;\r\n border-color: #3b82f6;\r\n background: white;\r\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\r\n}\r\n\r\n.auth-input:disabled {\r\n opacity: 0.6;\r\n cursor: not-allowed;\r\n}\r\n\r\n.auth-theme-dark .auth-input {\r\n background: #0f172a;\r\n border-color: #334155;\r\n color: #f1f5f9;\r\n}\r\n\r\n.auth-theme-dark .auth-input:focus {\r\n background: #1e293b;\r\n border-color: #3b82f6;\r\n}\r\n\r\n.auth-form-footer {\r\n display: flex;\r\n justify-content: flex-end;\r\n margin-bottom: 1.5rem;\r\n}\r\n\r\n.auth-link {\r\n background: none;\r\n border: none;\r\n padding: 0;\r\n font-size: 0.875rem;\r\n color: #3b82f6;\r\n cursor: pointer;\r\n transition: color 0.2s ease;\r\n}\r\n\r\n.auth-link:hover:not(:disabled) {\r\n color: #1d4ed8;\r\n text-decoration: underline;\r\n}\r\n\r\n.auth-link:disabled {\r\n opacity: 0.6;\r\n cursor: not-allowed;\r\n}\r\n\r\n.auth-link-bold {\r\n font-weight: 600;\r\n}\r\n\r\n.auth-button {\r\n width: 100%;\r\n padding: 0.875rem 1.5rem;\r\n font-size: 1rem;\r\n font-weight: 600;\r\n border: none;\r\n border-radius: 0.5rem;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 0.5rem;\r\n}\r\n\r\n.auth-button:disabled {\r\n opacity: 0.6;\r\n cursor: not-allowed;\r\n}\r\n\r\n.auth-button-primary {\r\n background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);\r\n color: white;\r\n box-shadow: 0 4px 12px rgba(59, 130, 246, 0.25);\r\n}\r\n\r\n.auth-button-primary:hover:not(:disabled) {\r\n transform: translateY(-2px);\r\n box-shadow: 0 6px 20px rgba(59, 130, 246, 0.35);\r\n}\r\n\r\n.auth-button-primary:active:not(:disabled) {\r\n transform: translateY(0);\r\n}\r\n\r\n.auth-button-secondary {\r\n background: white;\r\n color: #334155;\r\n border: 1px solid #e2e8f0;\r\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);\r\n}\r\n\r\n.auth-button-secondary:hover:not(:disabled) {\r\n background: #f8fafc;\r\n border-color: #cbd5e1;\r\n}\r\n\r\n.auth-theme-dark .auth-button-secondary {\r\n background: #0f172a;\r\n color: #f1f5f9;\r\n border-color: #334155;\r\n}\r\n\r\n.auth-theme-dark .auth-button-secondary:hover:not(:disabled) {\r\n background: #1e293b;\r\n border-color: #475569;\r\n}\r\n\r\n.auth-spinner {\r\n display: inline-block;\r\n width: 18px;\r\n height: 18px;\r\n border: 2px solid rgba(255, 255, 255, 0.3);\r\n border-top-color: white;\r\n border-radius: 50%;\r\n animation: spin 0.8s linear infinite;\r\n}\r\n\r\n@keyframes spin {\r\n to { transform: rotate(360deg); }\r\n}\r\n\r\n.auth-divider {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 0.5rem;\r\n margin-top: 1.5rem;\r\n font-size: 0.875rem;\r\n color: #64748b;\r\n}\r\n\r\n.auth-theme-dark .auth-divider {\r\n color: #94a3b8;\r\n}\r\n\r\n.auth-provider-buttons {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 0.75rem;\r\n margin-top: 1.5rem;\r\n}\r\n\r\n.auth-provider-button {\r\n width: 100%;\r\n padding: 0.875rem 1.5rem;\r\n font-size: 0.9375rem;\r\n font-weight: 500;\r\n background: white;\r\n color: #334155;\r\n border: 1px solid #e2e8f0;\r\n border-radius: 0.5rem;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 0.75rem;\r\n}\r\n\r\n.auth-provider-button:hover:not(:disabled) {\r\n background: #f8fafc;\r\n border-color: #cbd5e1;\r\n transform: translateY(-1px);\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\r\n}\r\n\r\n.auth-provider-button:disabled {\r\n opacity: 0.6;\r\n cursor: not-allowed;\r\n}\r\n\r\n.auth-theme-dark .auth-provider-button {\r\n background: #0f172a;\r\n color: #f1f5f9;\r\n border-color: #334155;\r\n}\r\n\r\n.auth-theme-dark .auth-provider-button:hover:not(:disabled) {\r\n background: #1e293b;\r\n border-color: #475569;\r\n}\r\n\r\n.auth-or-divider {\r\n display: flex;\r\n align-items: center;\r\n text-align: center;\r\n margin: 1.5rem 0;\r\n color: #94a3b8;\r\n font-size: 0.875rem;\r\n}\r\n\r\n.auth-or-divider::before,\r\n.auth-or-divider::after {\r\n content: '';\r\n flex: 1;\r\n border-bottom: 1px solid #e2e8f0;\r\n}\r\n\r\n.auth-or-divider span {\r\n padding: 0 1rem;\r\n}\r\n\r\n.auth-theme-dark .auth-or-divider::before,\r\n.auth-theme-dark .auth-or-divider::after {\r\n border-color: #334155;\r\n}\r\n\r\n@media (max-width: 640px) {\r\n .auth-form-title {\r\n font-size: 1.25rem;\r\n }\r\n \r\n .auth-button,\r\n .auth-provider-button {\r\n padding: 0.75rem 1rem;\r\n font-size: 0.9375rem;\r\n }\r\n}\r\n"]}
|