@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olwiba/ui",
3
- "version": "0.0.28",
3
+ "version": "0.0.30",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -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({ onSubmit, onSso, signUpHref = '#', forgotPasswordHref = '#', brand }: AuthFormProps) {
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>Enter your email and password to continue.</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
- <a className="text-xs text-muted-foreground underline underline-offset-4 hover:text-foreground" href={forgotPasswordHref}>
81
- Forgot password?
82
- </a>
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 id="auth-password" type="password" placeholder="••••••••" />
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">Continue</Button>
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}>Use SSO</Button>
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
- {signUpHref && (
95
- <p className="text-center text-xs text-muted-foreground">
96
- New here?{' '}
97
- <a className="text-foreground underline underline-offset-4" href={signUpHref}>
98
- Create an account
99
- </a>
100
- </p>
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 sign-in form. */
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;