@object-ui/auth 4.6.0 → 4.8.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/CHANGELOG.md +12 -0
- package/dist/AuthShell.d.ts +68 -0
- package/dist/AuthShell.d.ts.map +1 -0
- package/dist/AuthShell.js +37 -0
- package/dist/ForgotPasswordForm.d.ts +7 -2
- package/dist/ForgotPasswordForm.d.ts.map +1 -1
- package/dist/ForgotPasswordForm.js +9 -5
- package/dist/LoginForm.d.ts +9 -2
- package/dist/LoginForm.d.ts.map +1 -1
- package/dist/LoginForm.js +7 -3
- package/dist/RegisterForm.d.ts +9 -2
- package/dist/RegisterForm.d.ts.map +1 -1
- package/dist/RegisterForm.js +7 -3
- package/dist/authStyles.d.ts +52 -0
- package/dist/authStyles.d.ts.map +1 -0
- package/dist/authStyles.js +44 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import React from 'react';
|
|
9
|
+
/**
|
|
10
|
+
* Optional brand panel content for the AuthShell aside.
|
|
11
|
+
* Renders to the right of the form on `md` and above.
|
|
12
|
+
*/
|
|
13
|
+
export interface AuthShellBrandPanel {
|
|
14
|
+
/** Brand name or product name shown at the top of the panel. */
|
|
15
|
+
brandName?: React.ReactNode;
|
|
16
|
+
/** Optional icon/logo node shown beside the brand name. */
|
|
17
|
+
brandIcon?: React.ReactNode;
|
|
18
|
+
/** Large headline copy. */
|
|
19
|
+
headline?: React.ReactNode;
|
|
20
|
+
/** Short supporting copy below the headline. */
|
|
21
|
+
subline?: React.ReactNode;
|
|
22
|
+
/** Optional small caption shown at the bottom of the brand panel. */
|
|
23
|
+
footer?: React.ReactNode;
|
|
24
|
+
}
|
|
25
|
+
export interface AuthShellProps {
|
|
26
|
+
/** Slot for the auth form (LoginForm / RegisterForm / etc.) */
|
|
27
|
+
children: React.ReactNode;
|
|
28
|
+
/** Brand panel content shown on the right on `md+` screens. Omit to hide. */
|
|
29
|
+
brand?: AuthShellBrandPanel;
|
|
30
|
+
/**
|
|
31
|
+
* Override the wrapper class for the form column.
|
|
32
|
+
* Defaults to a centred flex column with comfortable padding.
|
|
33
|
+
*/
|
|
34
|
+
formColumnClassName?: string;
|
|
35
|
+
/** Override the wrapper class for the brand column. */
|
|
36
|
+
brandColumnClassName?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Optional class for the outermost root element.
|
|
39
|
+
* Defaults to a full-viewport two-column grid.
|
|
40
|
+
*/
|
|
41
|
+
className?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Premium split-screen auth shell. Use as a wrapper around any of the auth
|
|
45
|
+
* form components (LoginForm, RegisterForm, ForgotPasswordForm) to give the
|
|
46
|
+
* sign-in experience a polished, branded look.
|
|
47
|
+
*
|
|
48
|
+
* The form column appears on the left, the brand panel on the right
|
|
49
|
+
* (collapsing to form-only on mobile). The brand panel uses a gradient
|
|
50
|
+
* built from the primary color, plus a soft mesh of radial highlights —
|
|
51
|
+
* everything rendered with Tailwind utility classes so no extra deps are
|
|
52
|
+
* needed in the consuming app.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```tsx
|
|
56
|
+
* <AuthShell
|
|
57
|
+
* brand={{
|
|
58
|
+
* brandName: 'Acme',
|
|
59
|
+
* headline: 'Welcome back.',
|
|
60
|
+
* subline: 'Sign in to continue building.',
|
|
61
|
+
* }}
|
|
62
|
+
* >
|
|
63
|
+
* <LoginForm onSuccess={() => navigate('/dashboard')} />
|
|
64
|
+
* </AuthShell>
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function AuthShell({ children, brand, className, formColumnClassName, brandColumnClassName, }: AuthShellProps): import("react/jsx-runtime").JSX.Element;
|
|
68
|
+
//# sourceMappingURL=AuthShell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthShell.d.ts","sourceRoot":"","sources":["../src/AuthShell.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,gEAAgE;IAChE,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,2DAA2D;IAC3D,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,gDAAgD;IAChD,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,qEAAqE;IACrE,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,6EAA6E;IAC7E,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,uDAAuD;IACvD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAUD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,KAAK,EACL,SAAS,EACT,mBAAmB,EACnB,oBAAoB,GACrB,EAAE,cAAc,2CAwDhB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
const DEFAULT_BRAND_CLASSES = 'relative hidden overflow-hidden bg-gradient-to-br from-primary via-primary to-primary/80 text-primary-foreground md:flex md:flex-col md:justify-between md:p-12 lg:p-16';
|
|
3
|
+
const DEFAULT_FORM_CLASSES = 'flex min-h-screen flex-col items-center justify-center bg-background px-4 py-10 sm:px-6 md:min-h-0 md:h-screen md:overflow-y-auto';
|
|
4
|
+
const DEFAULT_ROOT_CLASSES = 'grid min-h-screen w-full md:grid-cols-2';
|
|
5
|
+
/**
|
|
6
|
+
* Premium split-screen auth shell. Use as a wrapper around any of the auth
|
|
7
|
+
* form components (LoginForm, RegisterForm, ForgotPasswordForm) to give the
|
|
8
|
+
* sign-in experience a polished, branded look.
|
|
9
|
+
*
|
|
10
|
+
* The form column appears on the left, the brand panel on the right
|
|
11
|
+
* (collapsing to form-only on mobile). The brand panel uses a gradient
|
|
12
|
+
* built from the primary color, plus a soft mesh of radial highlights —
|
|
13
|
+
* everything rendered with Tailwind utility classes so no extra deps are
|
|
14
|
+
* needed in the consuming app.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* <AuthShell
|
|
19
|
+
* brand={{
|
|
20
|
+
* brandName: 'Acme',
|
|
21
|
+
* headline: 'Welcome back.',
|
|
22
|
+
* subline: 'Sign in to continue building.',
|
|
23
|
+
* }}
|
|
24
|
+
* >
|
|
25
|
+
* <LoginForm onSuccess={() => navigate('/dashboard')} />
|
|
26
|
+
* </AuthShell>
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function AuthShell({ children, brand, className, formColumnClassName, brandColumnClassName, }) {
|
|
30
|
+
return (_jsxs("div", { className: className ?? DEFAULT_ROOT_CLASSES, children: [_jsx("div", { className: formColumnClassName ?? DEFAULT_FORM_CLASSES, children: _jsx("div", { className: "w-full max-w-md", children: children }) }), brand && (_jsxs("aside", { className: brandColumnClassName ?? DEFAULT_BRAND_CLASSES, "aria-hidden": "true", children: [_jsx("div", { className: "absolute inset-0 opacity-70", style: {
|
|
31
|
+
backgroundImage: 'radial-gradient(circle at 18% 22%, rgba(255,255,255,0.22), transparent 45%), radial-gradient(circle at 82% 78%, rgba(255,255,255,0.18), transparent 50%), radial-gradient(circle at 60% 20%, rgba(255,255,255,0.10), transparent 55%)',
|
|
32
|
+
} }), _jsx("div", { className: "absolute inset-0 opacity-[0.08]", style: {
|
|
33
|
+
backgroundImage: 'linear-gradient(to right, currentColor 1px, transparent 1px), linear-gradient(to bottom, currentColor 1px, transparent 1px)',
|
|
34
|
+
backgroundSize: '36px 36px',
|
|
35
|
+
maskImage: 'radial-gradient(circle at center, black 30%, transparent 75%)',
|
|
36
|
+
} }), _jsx("div", { className: "pointer-events-none absolute -right-24 top-1/3 h-72 w-72 rounded-full bg-white/20 blur-3xl" }), _jsx("div", { className: "pointer-events-none absolute -left-16 bottom-12 h-64 w-64 rounded-full bg-white/10 blur-3xl" }), _jsxs("div", { className: "relative z-10 flex items-center gap-3 text-sm font-medium uppercase tracking-[0.18em] opacity-90", children: [brand.brandIcon && _jsx("span", { "aria-hidden": "true", children: brand.brandIcon }), brand.brandName && _jsx("span", { children: brand.brandName })] }), _jsxs("div", { className: "relative z-10 max-w-md space-y-5", children: [brand.headline && (_jsx("h2", { className: "text-3xl font-semibold leading-tight tracking-tight md:text-4xl", children: brand.headline })), brand.subline && (_jsx("p", { className: "text-base leading-relaxed text-primary-foreground/85 md:text-lg", children: brand.subline }))] }), brand.footer && (_jsx("div", { className: "relative z-10 text-xs text-primary-foreground/70", children: brand.footer }))] }))] }));
|
|
37
|
+
}
|
|
@@ -30,14 +30,19 @@ export interface ForgotPasswordFormProps {
|
|
|
30
30
|
title?: string;
|
|
31
31
|
/** Custom description */
|
|
32
32
|
description?: string;
|
|
33
|
+
/** Custom icon shown above the title (defaults to a small key disc) */
|
|
34
|
+
icon?: React.ReactNode;
|
|
33
35
|
/** Custom link component for SPA navigation (e.g. React Router's Link) */
|
|
34
36
|
linkComponent?: React.ComponentType<AuthLinkComponentProps>;
|
|
35
37
|
/** Override default labels for i18n */
|
|
36
38
|
labels?: ForgotPasswordFormLabels;
|
|
39
|
+
/** Hide the icon disc above the form title. Defaults to false. */
|
|
40
|
+
hideIcon?: boolean;
|
|
37
41
|
}
|
|
38
42
|
/**
|
|
39
43
|
* Forgot password form component.
|
|
40
|
-
* Sends a password reset email to the user.
|
|
44
|
+
* Sends a password reset email to the user. Drop inside an `AuthShell`
|
|
45
|
+
* for a polished split-screen experience.
|
|
41
46
|
*
|
|
42
47
|
* @example
|
|
43
48
|
* ```tsx
|
|
@@ -47,5 +52,5 @@ export interface ForgotPasswordFormProps {
|
|
|
47
52
|
* />
|
|
48
53
|
* ```
|
|
49
54
|
*/
|
|
50
|
-
export declare function ForgotPasswordForm({ onSuccess, onError, loginUrl, title, description, linkComponent: LinkComp, labels, }: ForgotPasswordFormProps): import("react/jsx-runtime").JSX.Element;
|
|
55
|
+
export declare function ForgotPasswordForm({ onSuccess, onError, loginUrl, title, description, icon, hideIcon, linkComponent: LinkComp, labels, }: ForgotPasswordFormProps): import("react/jsx-runtime").JSX.Element;
|
|
51
56
|
//# sourceMappingURL=ForgotPasswordForm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ForgotPasswordForm.d.ts","sourceRoot":"","sources":["../src/ForgotPasswordForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"ForgotPasswordForm.d.ts","sourceRoot":"","sources":["../src/ForgotPasswordForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAYtD,qDAAqD;AACrD,MAAM,WAAW,wBAAwB;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,wBAAwB;IACxB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAqBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,SAAS,EACT,OAAO,EACP,QAAmB,EACnB,KAA6B,EAC7B,WAAyF,EACzF,IAAI,EACJ,QAAgB,EAChB,aAAa,EAAE,QAAsB,EACrC,MAAW,GACZ,EAAE,uBAAuB,2CAyGzB"}
|
|
@@ -8,10 +8,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
8
8
|
*/
|
|
9
9
|
import { useState } from 'react';
|
|
10
10
|
import { useAuth } from './useAuth';
|
|
11
|
+
import { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthErrorBanner, AuthFormHeader, AuthMailIcon, AuthSpinner, } from './authStyles';
|
|
11
12
|
const DefaultLink = ({ href, className, children }) => (_jsx("a", { href: href, className: className, children: children }));
|
|
13
|
+
const DefaultKeyIcon = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round", className: "h-6 w-6", "aria-hidden": "true", children: _jsx("path", { d: "M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4" }) }));
|
|
12
14
|
/**
|
|
13
15
|
* Forgot password form component.
|
|
14
|
-
* Sends a password reset email to the user.
|
|
16
|
+
* Sends a password reset email to the user. Drop inside an `AuthShell`
|
|
17
|
+
* for a polished split-screen experience.
|
|
15
18
|
*
|
|
16
19
|
* @example
|
|
17
20
|
* ```tsx
|
|
@@ -21,7 +24,7 @@ const DefaultLink = ({ href, className, children }) => (_jsx("a", { href: href,
|
|
|
21
24
|
* />
|
|
22
25
|
* ```
|
|
23
26
|
*/
|
|
24
|
-
export function ForgotPasswordForm({ onSuccess, onError, loginUrl = '/login', title = 'Reset your password', description =
|
|
27
|
+
export function ForgotPasswordForm({ onSuccess, onError, loginUrl = '/login', title = 'Reset your password', description = "Enter your email address and we'll send you a link to reset your password", icon, hideIcon = false, linkComponent: LinkComp = DefaultLink, labels = {}, }) {
|
|
25
28
|
const { forgotPassword, isLoading } = useAuth();
|
|
26
29
|
const [email, setEmail] = useState('');
|
|
27
30
|
const [error, setError] = useState(null);
|
|
@@ -32,7 +35,8 @@ export function ForgotPasswordForm({ onSuccess, onError, loginUrl = '/login', ti
|
|
|
32
35
|
submitButton: labels.submitButton ?? 'Send Reset Link',
|
|
33
36
|
submittingButton: labels.submittingButton ?? 'Sending...',
|
|
34
37
|
successTitle: labels.successTitle ?? 'Check your email',
|
|
35
|
-
successDescription: labels.successDescription ??
|
|
38
|
+
successDescription: labels.successDescription ??
|
|
39
|
+
"We've sent a password reset link to {{email}}. Please check your inbox.",
|
|
36
40
|
backToSignInText: labels.backToSignInText ?? 'Back to sign in',
|
|
37
41
|
rememberPasswordText: labels.rememberPasswordText ?? 'Remember your password?',
|
|
38
42
|
signInText: labels.signInText ?? 'Sign in',
|
|
@@ -55,7 +59,7 @@ export function ForgotPasswordForm({ onSuccess, onError, loginUrl = '/login', ti
|
|
|
55
59
|
const successMsg = l.successDescription.includes('{{email}}')
|
|
56
60
|
? l.successDescription.replace('{{email}}', email)
|
|
57
61
|
: `${l.successDescription} ${email}`;
|
|
58
|
-
return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-
|
|
62
|
+
return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: _jsx("span", { className: "flex h-12 w-12 items-center justify-center rounded-2xl bg-emerald-500/10 text-emerald-600 ring-1 ring-emerald-500/15 dark:text-emerald-400", children: _jsx(AuthMailIcon, {}) }), title: l.successTitle, description: successMsg }), loginUrl && (_jsx("p", { className: "text-center text-sm text-muted-foreground", children: _jsxs(LinkComp, { href: loginUrl, className: AUTH_LINK_CLASS, children: ["\u2190 ", l.backToSignInText] }) }))] }));
|
|
59
63
|
}
|
|
60
|
-
return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-
|
|
64
|
+
return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: hideIcon ? undefined : (icon ?? _jsx(DefaultKeyIcon, {})), title: title, description: description }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "forgot-email", className: AUTH_FIELD_LABEL_CLASS, children: l.emailLabel }), _jsx("input", { id: "forgot-email", type: "email", placeholder: l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "email", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("button", { type: "submit", disabled: isLoading, className: AUTH_PRIMARY_BUTTON_CLASS, children: [isLoading && _jsx(AuthSpinner, {}), isLoading ? l.submittingButton : l.submitButton] })] }), loginUrl && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.rememberPasswordText, ' ', _jsx(LinkComp, { href: loginUrl, className: AUTH_LINK_CLASS, children: l.signInText })] }))] }));
|
|
61
65
|
}
|
package/dist/LoginForm.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export interface LoginFormLabels {
|
|
|
18
18
|
submittingButton?: string;
|
|
19
19
|
noAccountText?: string;
|
|
20
20
|
signUpText?: string;
|
|
21
|
+
/** Divider label between social sign-in and email/password (defaults to "or") */
|
|
22
|
+
orText?: string;
|
|
21
23
|
}
|
|
22
24
|
export interface LoginFormProps {
|
|
23
25
|
/** Callback on successful login */
|
|
@@ -32,14 +34,19 @@ export interface LoginFormProps {
|
|
|
32
34
|
title?: string;
|
|
33
35
|
/** Custom description */
|
|
34
36
|
description?: string;
|
|
37
|
+
/** Custom icon shown above the title (defaults to a small lock disc) */
|
|
38
|
+
icon?: React.ReactNode;
|
|
35
39
|
/** Custom link component for SPA navigation (e.g. React Router's Link) */
|
|
36
40
|
linkComponent?: React.ComponentType<AuthLinkComponentProps>;
|
|
37
41
|
/** Override default labels for i18n */
|
|
38
42
|
labels?: LoginFormLabels;
|
|
43
|
+
/** Hide the icon disc above the form title. Defaults to false. */
|
|
44
|
+
hideIcon?: boolean;
|
|
39
45
|
}
|
|
40
46
|
/**
|
|
41
47
|
* Login form component with email/password authentication.
|
|
42
|
-
* Uses Tailwind CSS utility classes for styling.
|
|
48
|
+
* Uses Tailwind CSS utility classes for styling. Drop inside an `AuthShell`
|
|
49
|
+
* for a polished split-screen experience.
|
|
43
50
|
*
|
|
44
51
|
* @example
|
|
45
52
|
* ```tsx
|
|
@@ -50,5 +57,5 @@ export interface LoginFormProps {
|
|
|
50
57
|
* />
|
|
51
58
|
* ```
|
|
52
59
|
*/
|
|
53
|
-
export declare function LoginForm({ onSuccess, onError, registerUrl, forgotPasswordUrl, title, description, linkComponent: LinkComp, labels, }: LoginFormProps): import("react/jsx-runtime").JSX.Element;
|
|
60
|
+
export declare function LoginForm({ onSuccess, onError, registerUrl, forgotPasswordUrl, title, description, icon, hideIcon, linkComponent: LinkComp, labels, }: LoginFormProps): import("react/jsx-runtime").JSX.Element;
|
|
54
61
|
//# sourceMappingURL=LoginForm.d.ts.map
|
package/dist/LoginForm.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../src/LoginForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../src/LoginForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAYtD,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,gCAAgC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,OAAO,EACP,WAAyB,EACzB,iBAAsC,EACtC,KAAiC,EACjC,WAAyD,EACzD,IAAI,EACJ,QAAgB,EAChB,aAAa,EAAE,QAAsB,EACrC,MAAW,GACZ,EAAE,cAAc,2CAsHhB"}
|
package/dist/LoginForm.js
CHANGED
|
@@ -9,10 +9,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
9
9
|
import { useState } from 'react';
|
|
10
10
|
import { useAuth } from './useAuth';
|
|
11
11
|
import { SocialSignInButtons } from './SocialSignInButtons';
|
|
12
|
+
import { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthDivider, AuthErrorBanner, AuthFormHeader, AuthSpinner, } from './authStyles';
|
|
12
13
|
const DefaultLink = ({ href, className, children }) => (_jsx("a", { href: href, className: className, children: children }));
|
|
14
|
+
const DefaultLockIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round", className: "h-6 w-6", "aria-hidden": "true", children: [_jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2" }), _jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })] }));
|
|
13
15
|
/**
|
|
14
16
|
* Login form component with email/password authentication.
|
|
15
|
-
* Uses Tailwind CSS utility classes for styling.
|
|
17
|
+
* Uses Tailwind CSS utility classes for styling. Drop inside an `AuthShell`
|
|
18
|
+
* for a polished split-screen experience.
|
|
16
19
|
*
|
|
17
20
|
* @example
|
|
18
21
|
* ```tsx
|
|
@@ -23,7 +26,7 @@ const DefaultLink = ({ href, className, children }) => (_jsx("a", { href: href,
|
|
|
23
26
|
* />
|
|
24
27
|
* ```
|
|
25
28
|
*/
|
|
26
|
-
export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgotPasswordUrl = '/forgot-password', title = 'Sign in to your account', description = 'Enter your email and password to continue', linkComponent: LinkComp = DefaultLink, labels = {}, }) {
|
|
29
|
+
export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgotPasswordUrl = '/forgot-password', title = 'Sign in to your account', description = 'Enter your email and password to continue', icon, hideIcon = false, linkComponent: LinkComp = DefaultLink, labels = {}, }) {
|
|
27
30
|
const { signIn, isLoading } = useAuth();
|
|
28
31
|
const [email, setEmail] = useState('');
|
|
29
32
|
const [password, setPassword] = useState('');
|
|
@@ -38,6 +41,7 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
|
|
|
38
41
|
submittingButton: labels.submittingButton ?? 'Signing in...',
|
|
39
42
|
noAccountText: labels.noAccountText ?? "Don't have an account?",
|
|
40
43
|
signUpText: labels.signUpText ?? 'Sign up',
|
|
44
|
+
orText: labels.orText ?? 'or',
|
|
41
45
|
};
|
|
42
46
|
const handleSubmit = async (e) => {
|
|
43
47
|
e.preventDefault();
|
|
@@ -52,5 +56,5 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
|
|
|
52
56
|
onError?.(authError);
|
|
53
57
|
}
|
|
54
58
|
};
|
|
55
|
-
return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-
|
|
59
|
+
return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: hideIcon ? undefined : (icon ?? _jsx(DefaultLockIcon, {})), title: title, description: description }), _jsxs("div", { className: "space-y-5", children: [_jsx(SocialSignInButtons, { mode: "sign-in" }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsx(AuthDivider, { label: l.orText }), error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-email", className: AUTH_FIELD_LABEL_CLASS, children: l.emailLabel }), _jsx("input", { id: "login-email", type: "email", placeholder: l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "email", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { htmlFor: "login-password", className: AUTH_FIELD_LABEL_CLASS, children: l.passwordLabel }), forgotPasswordUrl && (_jsx(LinkComp, { href: forgotPasswordUrl, className: "text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.forgotPasswordText }))] }), _jsx("input", { id: "login-password", type: "password", placeholder: l.passwordPlaceholder, value: password, onChange: (e) => setPassword(e.target.value), required: true, autoComplete: "current-password", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("button", { type: "submit", disabled: isLoading, className: AUTH_PRIMARY_BUTTON_CLASS, children: [isLoading && _jsx(AuthSpinner, {}), isLoading ? l.submittingButton : l.submitButton] })] })] }), registerUrl && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.noAccountText, ' ', _jsx(LinkComp, { href: registerUrl, className: AUTH_LINK_CLASS, children: l.signUpText })] }))] }));
|
|
56
60
|
}
|
package/dist/RegisterForm.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface RegisterFormLabels {
|
|
|
23
23
|
submittingButton?: string;
|
|
24
24
|
hasAccountText?: string;
|
|
25
25
|
signInText?: string;
|
|
26
|
+
/** Divider label between social sign-up and email/password (defaults to "or") */
|
|
27
|
+
orText?: string;
|
|
26
28
|
}
|
|
27
29
|
export interface RegisterFormProps {
|
|
28
30
|
/** Callback on successful registration */
|
|
@@ -35,14 +37,19 @@ export interface RegisterFormProps {
|
|
|
35
37
|
title?: string;
|
|
36
38
|
/** Custom description */
|
|
37
39
|
description?: string;
|
|
40
|
+
/** Custom icon shown above the title (defaults to a small user-plus disc) */
|
|
41
|
+
icon?: React.ReactNode;
|
|
38
42
|
/** Custom link component for SPA navigation (e.g. React Router's Link) */
|
|
39
43
|
linkComponent?: React.ComponentType<AuthLinkComponentProps>;
|
|
40
44
|
/** Override default labels for i18n */
|
|
41
45
|
labels?: RegisterFormLabels;
|
|
46
|
+
/** Hide the icon disc above the form title. Defaults to false. */
|
|
47
|
+
hideIcon?: boolean;
|
|
42
48
|
}
|
|
43
49
|
/**
|
|
44
50
|
* Registration form component with name, email, and password fields.
|
|
45
|
-
* Uses Tailwind CSS utility classes for styling.
|
|
51
|
+
* Uses Tailwind CSS utility classes for styling. Drop inside an `AuthShell`
|
|
52
|
+
* for a polished split-screen experience.
|
|
46
53
|
*
|
|
47
54
|
* @example
|
|
48
55
|
* ```tsx
|
|
@@ -52,5 +59,5 @@ export interface RegisterFormProps {
|
|
|
52
59
|
* />
|
|
53
60
|
* ```
|
|
54
61
|
*/
|
|
55
|
-
export declare function RegisterForm({ onSuccess, onError, loginUrl, title, description, linkComponent: LinkComp, labels, }: RegisterFormProps): import("react/jsx-runtime").JSX.Element;
|
|
62
|
+
export declare function RegisterForm({ onSuccess, onError, loginUrl, title, description, icon, hideIcon, linkComponent: LinkComp, labels, }: RegisterFormProps): import("react/jsx-runtime").JSX.Element;
|
|
56
63
|
//# sourceMappingURL=RegisterForm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RegisterForm.d.ts","sourceRoot":"","sources":["../src/RegisterForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"RegisterForm.d.ts","sourceRoot":"","sources":["../src/RegisterForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAYtD,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,qCAAqC;IACrC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAwBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,OAAO,EACP,QAAmB,EACnB,KAA2B,EAC3B,WAAqD,EACrD,IAAI,EACJ,QAAgB,EAChB,aAAa,EAAE,QAAsB,EACrC,MAAW,GACZ,EAAE,iBAAiB,2CA6JnB"}
|
package/dist/RegisterForm.js
CHANGED
|
@@ -9,10 +9,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
9
9
|
import { useState } from 'react';
|
|
10
10
|
import { useAuth } from './useAuth';
|
|
11
11
|
import { SocialSignInButtons } from './SocialSignInButtons';
|
|
12
|
+
import { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthDivider, AuthErrorBanner, AuthFormHeader, AuthSpinner, } from './authStyles';
|
|
12
13
|
const DefaultLink = ({ href, className, children }) => (_jsx("a", { href: href, className: className, children: children }));
|
|
14
|
+
const DefaultUserPlusIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round", className: "h-6 w-6", "aria-hidden": "true", children: [_jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }), _jsx("circle", { cx: "9", cy: "7", r: "4" }), _jsx("line", { x1: "19", y1: "8", x2: "19", y2: "14" }), _jsx("line", { x1: "22", y1: "11", x2: "16", y2: "11" })] }));
|
|
13
15
|
/**
|
|
14
16
|
* Registration form component with name, email, and password fields.
|
|
15
|
-
* Uses Tailwind CSS utility classes for styling.
|
|
17
|
+
* Uses Tailwind CSS utility classes for styling. Drop inside an `AuthShell`
|
|
18
|
+
* for a polished split-screen experience.
|
|
16
19
|
*
|
|
17
20
|
* @example
|
|
18
21
|
* ```tsx
|
|
@@ -22,7 +25,7 @@ const DefaultLink = ({ href, className, children }) => (_jsx("a", { href: href,
|
|
|
22
25
|
* />
|
|
23
26
|
* ```
|
|
24
27
|
*/
|
|
25
|
-
export function RegisterForm({ onSuccess, onError, loginUrl = '/login', title = 'Create an account', description = 'Enter your information to get started', linkComponent: LinkComp = DefaultLink, labels = {}, }) {
|
|
28
|
+
export function RegisterForm({ onSuccess, onError, loginUrl = '/login', title = 'Create an account', description = 'Enter your information to get started', icon, hideIcon = false, linkComponent: LinkComp = DefaultLink, labels = {}, }) {
|
|
26
29
|
const { signUp, isLoading } = useAuth();
|
|
27
30
|
const [name, setName] = useState('');
|
|
28
31
|
const [email, setEmail] = useState('');
|
|
@@ -44,6 +47,7 @@ export function RegisterForm({ onSuccess, onError, loginUrl = '/login', title =
|
|
|
44
47
|
submittingButton: labels.submittingButton ?? 'Creating account...',
|
|
45
48
|
hasAccountText: labels.hasAccountText ?? 'Already have an account?',
|
|
46
49
|
signInText: labels.signInText ?? 'Sign in',
|
|
50
|
+
orText: labels.orText ?? 'or',
|
|
47
51
|
};
|
|
48
52
|
const handleSubmit = async (e) => {
|
|
49
53
|
e.preventDefault();
|
|
@@ -66,5 +70,5 @@ export function RegisterForm({ onSuccess, onError, loginUrl = '/login', title =
|
|
|
66
70
|
onError?.(authError);
|
|
67
71
|
}
|
|
68
72
|
};
|
|
69
|
-
return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-
|
|
73
|
+
return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: hideIcon ? undefined : (icon ?? _jsx(DefaultUserPlusIcon, {})), title: title, description: description }), _jsxs("div", { className: "space-y-5", children: [_jsx(SocialSignInButtons, { mode: "sign-up" }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsx(AuthDivider, { label: l.orText }), error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-name", className: AUTH_FIELD_LABEL_CLASS, children: l.nameLabel }), _jsx("input", { id: "register-name", type: "text", placeholder: l.namePlaceholder, value: name, onChange: (e) => setName(e.target.value), required: true, autoComplete: "name", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-email", className: AUTH_FIELD_LABEL_CLASS, children: l.emailLabel }), _jsx("input", { id: "register-email", type: "email", placeholder: l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "email", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-password", className: AUTH_FIELD_LABEL_CLASS, children: l.passwordLabel }), _jsx("input", { id: "register-password", type: "password", placeholder: l.passwordPlaceholder, value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "register-confirm-password", className: AUTH_FIELD_LABEL_CLASS, children: l.confirmPasswordLabel }), _jsx("input", { id: "register-confirm-password", type: "password", placeholder: l.confirmPasswordPlaceholder, value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), required: true, minLength: 8, autoComplete: "new-password", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("button", { type: "submit", disabled: isLoading, className: AUTH_PRIMARY_BUTTON_CLASS, children: [isLoading && _jsx(AuthSpinner, {}), isLoading ? l.submittingButton : l.submitButton] })] })] }), loginUrl && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.hasAccountText, ' ', _jsx(LinkComp, { href: loginUrl, className: AUTH_LINK_CLASS, children: l.signInText })] }))] }));
|
|
70
74
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import React from 'react';
|
|
9
|
+
/**
|
|
10
|
+
* Shared Tailwind utility classes for auth form primitives.
|
|
11
|
+
* These mirror the look used across LoginForm / RegisterForm /
|
|
12
|
+
* ForgotPasswordForm so the package presents a coherent feel.
|
|
13
|
+
*
|
|
14
|
+
* Consumers can override styling per-form by passing their own children
|
|
15
|
+
* inside an AuthShell, but the defaults aim to look premium out of the box.
|
|
16
|
+
*/
|
|
17
|
+
export declare const AUTH_INPUT_CLASS = "flex h-11 w-full rounded-lg border border-input bg-background px-3.5 py-2 text-sm shadow-sm ring-offset-background transition-colors placeholder:text-muted-foreground hover:border-primary/40 focus-visible:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50";
|
|
18
|
+
export declare const AUTH_PRIMARY_BUTTON_CLASS = "inline-flex h-11 w-full items-center justify-center gap-2 rounded-lg bg-gradient-to-r from-primary to-primary/85 px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm ring-offset-background transition-all hover:shadow-md hover:from-primary hover:to-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2 active:scale-[0.99] disabled:pointer-events-none disabled:opacity-60";
|
|
19
|
+
export declare const AUTH_FIELD_LABEL_CLASS = "text-sm font-medium leading-none text-foreground";
|
|
20
|
+
export declare const AUTH_LINK_CLASS = "font-medium text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:underline";
|
|
21
|
+
/** Decorative spinner shown while a submit is pending. */
|
|
22
|
+
export declare function AuthSpinner(): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
/** Inline alert icon for the error banner. */
|
|
24
|
+
export declare function AuthAlertIcon({ className }: {
|
|
25
|
+
className?: string;
|
|
26
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
/** Inline success check icon for confirmation states. */
|
|
28
|
+
export declare function AuthCheckIcon({ className }: {
|
|
29
|
+
className?: string;
|
|
30
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
/** Inline mail icon for the forgot-password success state. */
|
|
32
|
+
export declare function AuthMailIcon({ className }: {
|
|
33
|
+
className?: string;
|
|
34
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
/**
|
|
36
|
+
* Decorative wrapper that renders the form title block:
|
|
37
|
+
* optional icon disc + title + description, centered.
|
|
38
|
+
*/
|
|
39
|
+
export declare function AuthFormHeader({ icon, title, description, }: {
|
|
40
|
+
icon?: React.ReactNode;
|
|
41
|
+
title: React.ReactNode;
|
|
42
|
+
description?: React.ReactNode;
|
|
43
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
/** Inline error banner used by all auth forms. */
|
|
45
|
+
export declare function AuthErrorBanner({ message }: {
|
|
46
|
+
message: string;
|
|
47
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
48
|
+
/** "or" divider used when social sign-in buttons are present. */
|
|
49
|
+
export declare function AuthDivider({ label }: {
|
|
50
|
+
label?: string;
|
|
51
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
52
|
+
//# sourceMappingURL=authStyles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authStyles.d.ts","sourceRoot":"","sources":["../src/authStyles.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,0XAC4V,CAAC;AAE1X,eAAO,MAAM,yBAAyB,8bACuZ,CAAC;AAE9b,eAAO,MAAM,sBAAsB,qDAAqD,CAAC;AAEzF,eAAO,MAAM,eAAe,mHACsF,CAAC;AAEnH,0DAA0D;AAC1D,wBAAgB,WAAW,4CAyB1B;AAED,8CAA8C;AAC9C,wBAAgB,aAAa,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,2CAiBlE;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,2CAgBlE;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,2CAgBjE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,KAAK,EACL,WAAW,GACZ,EAAE;IACD,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC/B,2CAgBA;AAED,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,2CAU/D;AAED,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,EAAE,KAAY,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,2CAW/D"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Shared Tailwind utility classes for auth form primitives.
|
|
4
|
+
* These mirror the look used across LoginForm / RegisterForm /
|
|
5
|
+
* ForgotPasswordForm so the package presents a coherent feel.
|
|
6
|
+
*
|
|
7
|
+
* Consumers can override styling per-form by passing their own children
|
|
8
|
+
* inside an AuthShell, but the defaults aim to look premium out of the box.
|
|
9
|
+
*/
|
|
10
|
+
export const AUTH_INPUT_CLASS = 'flex h-11 w-full rounded-lg border border-input bg-background px-3.5 py-2 text-sm shadow-sm ring-offset-background transition-colors placeholder:text-muted-foreground hover:border-primary/40 focus-visible:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50';
|
|
11
|
+
export const AUTH_PRIMARY_BUTTON_CLASS = 'inline-flex h-11 w-full items-center justify-center gap-2 rounded-lg bg-gradient-to-r from-primary to-primary/85 px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm ring-offset-background transition-all hover:shadow-md hover:from-primary hover:to-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2 active:scale-[0.99] disabled:pointer-events-none disabled:opacity-60';
|
|
12
|
+
export const AUTH_FIELD_LABEL_CLASS = 'text-sm font-medium leading-none text-foreground';
|
|
13
|
+
export const AUTH_LINK_CLASS = 'font-medium text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:underline';
|
|
14
|
+
/** Decorative spinner shown while a submit is pending. */
|
|
15
|
+
export function AuthSpinner() {
|
|
16
|
+
return (_jsxs("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-90", d: "M4 12a8 8 0 018-8", stroke: "currentColor", strokeWidth: "4", strokeLinecap: "round" })] }));
|
|
17
|
+
}
|
|
18
|
+
/** Inline alert icon for the error banner. */
|
|
19
|
+
export function AuthAlertIcon({ className }) {
|
|
20
|
+
return (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: className ?? 'h-4 w-4 shrink-0', "aria-hidden": "true", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }), _jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })] }));
|
|
21
|
+
}
|
|
22
|
+
/** Inline success check icon for confirmation states. */
|
|
23
|
+
export function AuthCheckIcon({ className }) {
|
|
24
|
+
return (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: className ?? 'h-6 w-6', "aria-hidden": "true", children: [_jsx("path", { d: "M22 11.08V12a10 10 0 11-5.93-9.14" }), _jsx("polyline", { points: "22 4 12 14.01 9 11.01" })] }));
|
|
25
|
+
}
|
|
26
|
+
/** Inline mail icon for the forgot-password success state. */
|
|
27
|
+
export function AuthMailIcon({ className }) {
|
|
28
|
+
return (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round", className: className ?? 'h-7 w-7', "aria-hidden": "true", children: [_jsx("rect", { x: "2", y: "4", width: "20", height: "16", rx: "2" }), _jsx("path", { d: "m22 6-10 7L2 6" })] }));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Decorative wrapper that renders the form title block:
|
|
32
|
+
* optional icon disc + title + description, centered.
|
|
33
|
+
*/
|
|
34
|
+
export function AuthFormHeader({ icon, title, description, }) {
|
|
35
|
+
return (_jsxs("div", { className: "flex flex-col items-center space-y-3 text-center", children: [icon && (_jsx("div", { className: "flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary ring-1 ring-primary/15", children: icon })), _jsx("h1", { className: "text-2xl font-semibold tracking-tight text-foreground sm:text-[1.6rem]", children: title }), description && (_jsx("p", { className: "text-sm leading-relaxed text-muted-foreground", children: description }))] }));
|
|
36
|
+
}
|
|
37
|
+
/** Inline error banner used by all auth forms. */
|
|
38
|
+
export function AuthErrorBanner({ message }) {
|
|
39
|
+
return (_jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-destructive/30 bg-destructive/10 p-3 text-sm text-destructive", role: "alert", children: [_jsx(AuthAlertIcon, { className: "mt-0.5 h-4 w-4 shrink-0" }), _jsx("span", { className: "leading-snug", children: message })] }));
|
|
40
|
+
}
|
|
41
|
+
/** "or" divider used when social sign-in buttons are present. */
|
|
42
|
+
export function AuthDivider({ label = 'or' }) {
|
|
43
|
+
return (_jsxs("div", { className: "relative my-1", children: [_jsx("div", { className: "absolute inset-0 flex items-center", "aria-hidden": "true", children: _jsx("span", { className: "w-full border-t border-border" }) }), _jsx("div", { className: "relative flex justify-center text-xs uppercase tracking-wider", children: _jsx("span", { className: "bg-background px-3 text-muted-foreground", children: label }) })] }));
|
|
44
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
export { AuthProvider, type AuthProviderProps } from './AuthProvider';
|
|
23
23
|
export { useAuth } from './useAuth';
|
|
24
24
|
export { AuthGuard, type AuthGuardProps } from './AuthGuard';
|
|
25
|
+
export { AuthShell, type AuthShellProps, type AuthShellBrandPanel } from './AuthShell';
|
|
25
26
|
export { LoginForm, type LoginFormProps, type LoginFormLabels } from './LoginForm';
|
|
26
27
|
export { RegisterForm, type RegisterFormProps, type RegisterFormLabels } from './RegisterForm';
|
|
27
28
|
export { ForgotPasswordForm, type ForgotPasswordFormProps, type ForgotPasswordFormLabels } from './ForgotPasswordForm';
|
|
@@ -31,6 +32,7 @@ export { PreviewBanner, type PreviewBannerProps } from './PreviewBanner';
|
|
|
31
32
|
export { createAuthClient, TokenStorage } from './createAuthClient';
|
|
32
33
|
export { createAuthenticatedFetch, ActiveOrganizationStorage, type AuthenticatedAdapterOptions } from './createAuthenticatedFetch';
|
|
33
34
|
export { getUserInitials } from './types';
|
|
35
|
+
export { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthAlertIcon, AuthCheckIcon, AuthDivider, AuthErrorBanner, AuthFormHeader, AuthMailIcon, AuthSpinner, } from './authStyles';
|
|
34
36
|
export type { AuthUser, AuthSession, AuthState, AuthClient, AuthClientConfig, AuthLinkComponentProps, AuthProviderConfig, PreviewModeOptions, SignInCredentials, SignUpData, AuthOrganization, AuthOrganizationMember, AuthInvitation, AuthSocialProvider, AuthPublicConfig, SignInWithProviderOptions, } from './types';
|
|
35
37
|
export type { AuthContextValue } from './AuthContext';
|
|
36
38
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACvH,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,KAAK,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACnI,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACvH,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,KAAK,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACnI,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI1C,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EACf,yBAAyB,EACzB,aAAa,EACb,aAAa,EACb,WAAW,EACX,eAAe,EACf,cAAc,EACd,YAAY,EACZ,WAAW,GACZ,MAAM,cAAc,CAAC;AAGtB,YAAY,EACV,QAAQ,EACR,WAAW,EACX,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,GAC1B,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
export { AuthProvider } from './AuthProvider';
|
|
23
23
|
export { useAuth } from './useAuth';
|
|
24
24
|
export { AuthGuard } from './AuthGuard';
|
|
25
|
+
export { AuthShell } from './AuthShell';
|
|
25
26
|
export { LoginForm } from './LoginForm';
|
|
26
27
|
export { RegisterForm } from './RegisterForm';
|
|
27
28
|
export { ForgotPasswordForm } from './ForgotPasswordForm';
|
|
@@ -31,3 +32,6 @@ export { PreviewBanner } from './PreviewBanner';
|
|
|
31
32
|
export { createAuthClient, TokenStorage } from './createAuthClient';
|
|
32
33
|
export { createAuthenticatedFetch, ActiveOrganizationStorage } from './createAuthenticatedFetch';
|
|
33
34
|
export { getUserInitials } from './types';
|
|
35
|
+
// Shared auth form primitives — exposed so consumers can build custom forms
|
|
36
|
+
// that match the look of LoginForm / RegisterForm / ForgotPasswordForm.
|
|
37
|
+
export { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthAlertIcon, AuthCheckIcon, AuthDivider, AuthErrorBanner, AuthFormHeader, AuthMailIcon, AuthSpinner, } from './authStyles';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/auth",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Authentication system for Object UI with AuthProvider, useAuth hook, AuthGuard, and form components.",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"better-auth": "^1.6.11",
|
|
34
|
-
"@object-ui/types": "4.
|
|
34
|
+
"@object-ui/types": "4.8.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/react": "19.2.14",
|