@olwiba/ui 0.0.28 → 0.0.30
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/dist/index.d.ts +13 -2
- package/dist/index.js +60 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/app/AuthSection.tsx +81 -22
package/package.json
CHANGED
package/src/app/AuthSection.tsx
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { GalleryVerticalEnd, Building2, ShieldCheck, Sparkles } from 'lucide-react';
|
|
5
5
|
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, Label, cn } from '@olwiba/cn';
|
|
6
|
+
import type { AppShellRenderLink } from './AppShell';
|
|
7
|
+
|
|
8
|
+
const defaultRenderLink: AppShellRenderLink = ({ href, children, className }) => (
|
|
9
|
+
<a href={href} className={className}>{children}</a>
|
|
10
|
+
);
|
|
6
11
|
|
|
7
12
|
// ─── Centered layout ──────────────────────────────────────────────────────────
|
|
8
13
|
|
|
@@ -52,53 +57,107 @@ function SplitAuth({ children, panel }: { children: React.ReactNode; panel?: Rea
|
|
|
52
57
|
// ─── Shared form slot ─────────────────────────────────────────────────────────
|
|
53
58
|
|
|
54
59
|
export interface AuthFormProps {
|
|
60
|
+
/** Controls form title, fields, and footer text. @default 'signin' */
|
|
61
|
+
mode?: 'signin' | 'signup';
|
|
55
62
|
onSubmit?: (e: React.FormEvent<HTMLFormElement>) => void;
|
|
56
63
|
onSso?: () => void;
|
|
64
|
+
/** (signin) Link to the sign-up page */
|
|
57
65
|
signUpHref?: string;
|
|
66
|
+
/** (signup) Link back to the sign-in page */
|
|
67
|
+
signInHref?: string;
|
|
58
68
|
forgotPasswordHref?: string;
|
|
59
69
|
brand?: React.ReactNode;
|
|
70
|
+
/** Error message displayed below the form fields */
|
|
71
|
+
error?: string;
|
|
72
|
+
/** Disables the submit button and shows a loading label */
|
|
73
|
+
loading?: boolean;
|
|
74
|
+
/** Render prop for links — use to inject framework-native link components (e.g. TanStack Router Link) */
|
|
75
|
+
renderLink?: AppShellRenderLink;
|
|
60
76
|
}
|
|
61
77
|
|
|
62
|
-
function DefaultForm({
|
|
78
|
+
function DefaultForm({
|
|
79
|
+
mode = 'signin',
|
|
80
|
+
onSubmit,
|
|
81
|
+
onSso,
|
|
82
|
+
signUpHref = '#',
|
|
83
|
+
signInHref = '#',
|
|
84
|
+
forgotPasswordHref = '#',
|
|
85
|
+
brand,
|
|
86
|
+
error,
|
|
87
|
+
loading,
|
|
88
|
+
renderLink = defaultRenderLink,
|
|
89
|
+
}: AuthFormProps) {
|
|
90
|
+
const isSignUp = mode === 'signup';
|
|
91
|
+
|
|
63
92
|
return (
|
|
64
93
|
<Card className="w-full max-w-md">
|
|
65
94
|
<CardHeader>
|
|
66
95
|
{brand && <div className="mb-2">{brand}</div>}
|
|
67
|
-
<CardTitle>Sign in</CardTitle>
|
|
68
|
-
<CardDescription>
|
|
96
|
+
<CardTitle>{isSignUp ? 'Create an account' : 'Sign in'}</CardTitle>
|
|
97
|
+
<CardDescription>
|
|
98
|
+
{isSignUp
|
|
99
|
+
? 'Enter your details to create your account.'
|
|
100
|
+
: 'Enter your email and password to continue.'}
|
|
101
|
+
</CardDescription>
|
|
69
102
|
</CardHeader>
|
|
70
103
|
<CardContent className="space-y-4">
|
|
71
104
|
<form onSubmit={onSubmit} className="space-y-4">
|
|
105
|
+
{isSignUp && (
|
|
106
|
+
<div className="space-y-2">
|
|
107
|
+
<Label htmlFor="auth-name">Name</Label>
|
|
108
|
+
<Input id="auth-name" name="name" type="text" placeholder="Your name" autoComplete="name" />
|
|
109
|
+
</div>
|
|
110
|
+
)}
|
|
72
111
|
<div className="space-y-2">
|
|
73
112
|
<Label htmlFor="auth-email">Email</Label>
|
|
74
|
-
<Input id="auth-email" type="email" placeholder="name@company.com" />
|
|
113
|
+
<Input id="auth-email" name="email" type="email" placeholder="name@company.com" autoComplete="email" />
|
|
75
114
|
</div>
|
|
76
115
|
<div className="space-y-2">
|
|
77
116
|
<div className="flex items-center justify-between">
|
|
78
117
|
<Label htmlFor="auth-password">Password</Label>
|
|
79
|
-
{forgotPasswordHref && (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
)}
|
|
118
|
+
{!isSignUp && forgotPasswordHref && renderLink({
|
|
119
|
+
href: forgotPasswordHref,
|
|
120
|
+
className: 'text-xs text-muted-foreground underline underline-offset-4 hover:text-foreground',
|
|
121
|
+
children: 'Forgot password?',
|
|
122
|
+
})}
|
|
84
123
|
</div>
|
|
85
|
-
<Input
|
|
124
|
+
<Input
|
|
125
|
+
id="auth-password"
|
|
126
|
+
name="password"
|
|
127
|
+
type="password"
|
|
128
|
+
placeholder="••••••••"
|
|
129
|
+
autoComplete={isSignUp ? 'new-password' : 'current-password'}
|
|
130
|
+
/>
|
|
86
131
|
</div>
|
|
132
|
+
{error && (
|
|
133
|
+
<p className="text-sm font-medium text-destructive">{error}</p>
|
|
134
|
+
)}
|
|
87
135
|
<div className="flex flex-col gap-2">
|
|
88
|
-
<Button type="submit" className="w-full">
|
|
136
|
+
<Button type="submit" className="w-full" disabled={loading}>
|
|
137
|
+
{loading ? 'Please wait…' : isSignUp ? 'Create account' : 'Sign in'}
|
|
138
|
+
</Button>
|
|
89
139
|
{onSso && (
|
|
90
|
-
<Button type="button" variant="outline" className="w-full" onClick={onSso}
|
|
140
|
+
<Button type="button" variant="outline" className="w-full" onClick={onSso} disabled={loading}>
|
|
141
|
+
Use SSO
|
|
142
|
+
</Button>
|
|
91
143
|
)}
|
|
92
144
|
</div>
|
|
93
145
|
</form>
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
146
|
+
<p className="text-center text-xs text-muted-foreground">
|
|
147
|
+
{isSignUp ? (
|
|
148
|
+
<>
|
|
149
|
+
Already have an account?{' '}
|
|
150
|
+
{renderLink({ href: signInHref, className: 'text-foreground underline underline-offset-4', children: 'Sign in' })}
|
|
151
|
+
</>
|
|
152
|
+
) : (
|
|
153
|
+
signUpHref && (
|
|
154
|
+
<>
|
|
155
|
+
New here?{' '}
|
|
156
|
+
{renderLink({ href: signUpHref, className: 'text-foreground underline underline-offset-4', children: 'Create an account' })}
|
|
157
|
+
</>
|
|
158
|
+
)
|
|
159
|
+
)}
|
|
160
|
+
</p>
|
|
102
161
|
</CardContent>
|
|
103
162
|
</Card>
|
|
104
163
|
);
|
|
@@ -107,9 +166,9 @@ function DefaultForm({ onSubmit, onSso, signUpHref = '#', forgotPasswordHref = '
|
|
|
107
166
|
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
108
167
|
|
|
109
168
|
export interface AuthSectionProps extends AuthFormProps {
|
|
110
|
-
/** Visual layout of the auth screen */
|
|
169
|
+
/** Visual layout of the auth screen. @default 'centered' */
|
|
111
170
|
layout?: 'centered' | 'split';
|
|
112
|
-
/** Custom form/card content. Defaults to the built-in
|
|
171
|
+
/** Custom form/card content. Defaults to the built-in form. */
|
|
113
172
|
children?: React.ReactNode;
|
|
114
173
|
/** (split layout only) Custom content for the left decorative panel */
|
|
115
174
|
panel?: React.ReactNode;
|