@olwiba/ui 0.0.29 → 0.0.32

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.29",
3
+ "version": "0.0.32",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -1,15 +1,28 @@
1
1
  'use client';
2
2
 
3
3
  import * as React from 'react';
4
- import { GalleryVerticalEnd, Building2, ShieldCheck, Sparkles } from 'lucide-react';
5
- import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, Label, cn } from '@olwiba/cn';
4
+ import { Building2, ShieldCheck, Sparkles } from 'lucide-react';
5
+ import { Badge, CardContent, CardDescription, CardHeader, CardTitle, Label, cn } from '@olwiba/cn';
6
+ import { Button } from '../primitives/Button';
7
+ import { Card } from '../primitives/Card';
8
+ import { Input } from '../primitives/Input';
9
+ import type { AppShellRenderLink } from './AppShell';
10
+
11
+ const defaultRenderLink: AppShellRenderLink = ({ href, children, className }) => (
12
+ <a href={href} className={className}>{children}</a>
13
+ );
6
14
 
7
15
  // ─── Centered layout ──────────────────────────────────────────────────────────
8
16
 
9
- function CenteredAuth({ children }: { children: React.ReactNode }) {
17
+ function CenteredAuth({ children, brand, className }: { children: React.ReactNode; brand?: React.ReactNode; className?: string }) {
10
18
  return (
11
- <section className="flex h-full min-h-[720px] w-full flex-col items-center justify-center gap-6 rounded-2xl bg-muted p-6 md:p-10">
12
- <div className="flex w-full max-w-sm flex-col gap-6">
19
+ <section className={cn('flex min-h-screen flex-col justify-center bg-background py-12 px-4 sm:px-6 lg:px-8', className)}>
20
+ {brand && (
21
+ <div className="mx-auto w-full max-w-md text-center mb-8">
22
+ {brand}
23
+ </div>
24
+ )}
25
+ <div className="mx-auto w-full max-w-md">
13
26
  {children}
14
27
  </div>
15
28
  </section>
@@ -61,11 +74,14 @@ export interface AuthFormProps {
61
74
  /** (signup) Link back to the sign-in page */
62
75
  signInHref?: string;
63
76
  forgotPasswordHref?: string;
77
+ /** Brand node — in centered layout renders above the card; in split layout renders inside the card */
64
78
  brand?: React.ReactNode;
65
79
  /** Error message displayed below the form fields */
66
80
  error?: string;
67
81
  /** Disables the submit button and shows a loading label */
68
82
  loading?: boolean;
83
+ /** Render prop for links — use to inject framework-native link components (e.g. TanStack Router Link) */
84
+ renderLink?: AppShellRenderLink;
69
85
  }
70
86
 
71
87
  function DefaultForm({
@@ -78,11 +94,12 @@ function DefaultForm({
78
94
  brand,
79
95
  error,
80
96
  loading,
97
+ renderLink = defaultRenderLink,
81
98
  }: AuthFormProps) {
82
99
  const isSignUp = mode === 'signup';
83
100
 
84
101
  return (
85
- <Card className="w-full max-w-md">
102
+ <Card className="w-full">
86
103
  <CardHeader>
87
104
  {brand && <div className="mb-2">{brand}</div>}
88
105
  <CardTitle>{isSignUp ? 'Create an account' : 'Sign in'}</CardTitle>
@@ -101,17 +118,17 @@ function DefaultForm({
101
118
  </div>
102
119
  )}
103
120
  <div className="space-y-2">
104
- <Label htmlFor="auth-email">Email</Label>
121
+ <Label htmlFor="auth-email">Email address</Label>
105
122
  <Input id="auth-email" name="email" type="email" placeholder="name@company.com" autoComplete="email" />
106
123
  </div>
107
124
  <div className="space-y-2">
108
125
  <div className="flex items-center justify-between">
109
126
  <Label htmlFor="auth-password">Password</Label>
110
- {!isSignUp && forgotPasswordHref && (
111
- <a className="text-xs text-muted-foreground underline underline-offset-4 hover:text-foreground" href={forgotPasswordHref}>
112
- Forgot password?
113
- </a>
114
- )}
127
+ {!isSignUp && forgotPasswordHref && renderLink({
128
+ href: forgotPasswordHref,
129
+ className: 'text-xs text-muted-foreground underline underline-offset-4 hover:text-foreground',
130
+ children: 'Forgot password?',
131
+ })}
115
132
  </div>
116
133
  <Input
117
134
  id="auth-password"
@@ -139,17 +156,13 @@ function DefaultForm({
139
156
  {isSignUp ? (
140
157
  <>
141
158
  Already have an account?{' '}
142
- <a className="text-foreground underline underline-offset-4" href={signInHref}>
143
- Sign in
144
- </a>
159
+ {renderLink({ href: signInHref, className: 'text-foreground underline underline-offset-4', children: 'Sign in' })}
145
160
  </>
146
161
  ) : (
147
162
  signUpHref && (
148
163
  <>
149
164
  New here?{' '}
150
- <a className="text-foreground underline underline-offset-4" href={signUpHref}>
151
- Create an account
152
- </a>
165
+ {renderLink({ href: signUpHref, className: 'text-foreground underline underline-offset-4', children: 'Create an account' })}
153
166
  </>
154
167
  )
155
168
  )}
@@ -178,9 +191,8 @@ export function AuthSection({
178
191
  className,
179
192
  ...formProps
180
193
  }: AuthSectionProps) {
181
- const form = children ?? <DefaultForm {...formProps} />;
182
-
183
194
  if (layout === 'split') {
195
+ const form = children ?? <DefaultForm {...formProps} />;
184
196
  return (
185
197
  <div className={cn('h-full', className)}>
186
198
  <SplitAuth panel={panel}>{form}</SplitAuth>
@@ -188,9 +200,12 @@ export function AuthSection({
188
200
  );
189
201
  }
190
202
 
203
+ // Centered: brand renders above the card, not inside it
204
+ const { brand, ...restFormProps } = formProps;
205
+ const form = children ?? <DefaultForm {...restFormProps} />;
191
206
  return (
192
- <div className={cn('h-full', className)}>
193
- <CenteredAuth>{form}</CenteredAuth>
194
- </div>
207
+ <CenteredAuth brand={brand} className={className}>
208
+ {form}
209
+ </CenteredAuth>
195
210
  );
196
211
  }