@dravyn/auth-ui 0.1.1

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.
Files changed (52) hide show
  1. package/dist/chunk-35G4WYX3.mjs +154 -0
  2. package/dist/chunk-35G4WYX3.mjs.map +1 -0
  3. package/dist/chunk-6BBGRN4E.mjs +1 -0
  4. package/dist/chunk-6BBGRN4E.mjs.map +1 -0
  5. package/dist/chunk-FAI3ERB3.mjs +209 -0
  6. package/dist/chunk-FAI3ERB3.mjs.map +1 -0
  7. package/dist/chunk-FVXZZTKL.mjs +152 -0
  8. package/dist/chunk-FVXZZTKL.mjs.map +1 -0
  9. package/dist/chunk-Z2ICX4UY.mjs +132 -0
  10. package/dist/chunk-Z2ICX4UY.mjs.map +1 -0
  11. package/dist/index.css +235 -0
  12. package/dist/index.css.map +1 -0
  13. package/dist/index.d.mts +5 -0
  14. package/dist/index.d.ts +5 -0
  15. package/dist/index.js +678 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/index.mjs +22 -0
  18. package/dist/index.mjs.map +1 -0
  19. package/dist/screens/ForgotResetScreen.css +235 -0
  20. package/dist/screens/ForgotResetScreen.css.map +1 -0
  21. package/dist/screens/ForgotResetScreen.d.mts +17 -0
  22. package/dist/screens/ForgotResetScreen.d.ts +17 -0
  23. package/dist/screens/ForgotResetScreen.js +245 -0
  24. package/dist/screens/ForgotResetScreen.js.map +1 -0
  25. package/dist/screens/ForgotResetScreen.mjs +11 -0
  26. package/dist/screens/ForgotResetScreen.mjs.map +1 -0
  27. package/dist/screens/LoginScreen.css +235 -0
  28. package/dist/screens/LoginScreen.css.map +1 -0
  29. package/dist/screens/LoginScreen.d.mts +36 -0
  30. package/dist/screens/LoginScreen.d.ts +36 -0
  31. package/dist/screens/LoginScreen.js +167 -0
  32. package/dist/screens/LoginScreen.js.map +1 -0
  33. package/dist/screens/LoginScreen.mjs +9 -0
  34. package/dist/screens/LoginScreen.mjs.map +1 -0
  35. package/dist/screens/OTPScreen.css +235 -0
  36. package/dist/screens/OTPScreen.css.map +1 -0
  37. package/dist/screens/OTPScreen.d.mts +16 -0
  38. package/dist/screens/OTPScreen.d.ts +16 -0
  39. package/dist/screens/OTPScreen.js +187 -0
  40. package/dist/screens/OTPScreen.js.map +1 -0
  41. package/dist/screens/OTPScreen.mjs +9 -0
  42. package/dist/screens/OTPScreen.mjs.map +1 -0
  43. package/dist/screens/RegisterScreen.css +235 -0
  44. package/dist/screens/RegisterScreen.css.map +1 -0
  45. package/dist/screens/RegisterScreen.d.mts +21 -0
  46. package/dist/screens/RegisterScreen.d.ts +21 -0
  47. package/dist/screens/RegisterScreen.js +189 -0
  48. package/dist/screens/RegisterScreen.js.map +1 -0
  49. package/dist/screens/RegisterScreen.mjs +9 -0
  50. package/dist/screens/RegisterScreen.mjs.map +1 -0
  51. package/package.json +39 -0
  52. package/src/screens/auth.css +260 -0
@@ -0,0 +1,245 @@
1
+ "use strict";
2
+ "use client";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/screens/ForgotResetScreen.tsx
32
+ var ForgotResetScreen_exports = {};
33
+ __export(ForgotResetScreen_exports, {
34
+ ForgotPasswordScreen: () => ForgotPasswordScreen,
35
+ ResetPasswordScreen: () => ResetPasswordScreen
36
+ });
37
+ module.exports = __toCommonJS(ForgotResetScreen_exports);
38
+ var import_react = __toESM(require("react"));
39
+ var import_ui = require("@dravyn/ui");
40
+ var import_ui2 = require("@dravyn/ui");
41
+ var import_ui3 = require("@dravyn/ui");
42
+ var ForgotPasswordScreen = ({
43
+ logo,
44
+ brandName = "Dravyn",
45
+ apiBase = process.env.NEXT_PUBLIC_AUTH_API_URL ?? "http://localhost:3001"
46
+ }) => {
47
+ const [email, setEmail] = import_react.default.useState("");
48
+ const [loading, setLoading] = import_react.default.useState(false);
49
+ const [error, setError] = import_react.default.useState("");
50
+ const [sent, setSent] = import_react.default.useState(false);
51
+ const handleSubmit = async (e) => {
52
+ e.preventDefault();
53
+ if (!email.trim()) {
54
+ setError("Email address is required.");
55
+ return;
56
+ }
57
+ if (!/\S+@\S+\.\S+/.test(email)) {
58
+ setError("Enter a valid email address.");
59
+ return;
60
+ }
61
+ setLoading(true);
62
+ setError("");
63
+ try {
64
+ const res = await fetch(`${apiBase}/auth/forgot-password`, {
65
+ method: "POST",
66
+ headers: { "Content-Type": "application/json" },
67
+ body: JSON.stringify({ email: email.trim().toLowerCase() })
68
+ });
69
+ if (res.ok || res.status === 404) {
70
+ sessionStorage.setItem("dravyn_reset_email", email.trim().toLowerCase());
71
+ setSent(true);
72
+ } else {
73
+ const d = await res.json();
74
+ setError(d.message ?? "Something went wrong. Try again.");
75
+ }
76
+ } catch {
77
+ setError("Unable to connect.");
78
+ } finally {
79
+ setLoading(false);
80
+ }
81
+ };
82
+ if (sent) {
83
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-root" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-card" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-brand" }, logo ?? /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-logo-default" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "dauth-logo-dot" }), brandName)), /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-otp-icon" }, "\u2713"), /* @__PURE__ */ import_react.default.createElement("h1", { className: "dauth-title" }, "Check your inbox"), /* @__PURE__ */ import_react.default.createElement("p", { className: "dauth-sub" }, "If ", /* @__PURE__ */ import_react.default.createElement("strong", { style: { color: "var(--dauth-text)" } }, email), " is registered, you'll receive a reset code shortly."), /* @__PURE__ */ import_react.default.createElement(
84
+ import_ui.Button,
85
+ {
86
+ variant: "primary",
87
+ fullWidth: true,
88
+ style: { marginTop: 20 },
89
+ onClick: () => window.location.href = "/auth/reset-password"
90
+ },
91
+ "Enter reset code"
92
+ ), /* @__PURE__ */ import_react.default.createElement("p", { className: "dauth-footer-text" }, /* @__PURE__ */ import_react.default.createElement("a", { href: "/auth/login", className: "dauth-link" }, "Back to sign in"))));
93
+ }
94
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-root" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-card" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-brand" }, logo ?? /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-logo-default" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "dauth-logo-dot" }), brandName)), /* @__PURE__ */ import_react.default.createElement("h1", { className: "dauth-title" }, "Reset your password"), /* @__PURE__ */ import_react.default.createElement("p", { className: "dauth-sub" }, "Enter your email and we'll send you a reset code."), error && /* @__PURE__ */ import_react.default.createElement("div", { style: { marginBottom: 14 } }, /* @__PURE__ */ import_react.default.createElement(import_ui3.Alert, { variant: "danger" }, error)), /* @__PURE__ */ import_react.default.createElement("form", { onSubmit: handleSubmit, noValidate: true }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-fields" }, /* @__PURE__ */ import_react.default.createElement(
95
+ import_ui2.Input,
96
+ {
97
+ label: "Email address",
98
+ type: "email",
99
+ placeholder: "you@example.com",
100
+ value: email,
101
+ onChange: (e) => setEmail(e.target.value),
102
+ autoComplete: "email",
103
+ required: true
104
+ }
105
+ )), /* @__PURE__ */ import_react.default.createElement(import_ui.Button, { type: "submit", variant: "primary", fullWidth: true, loading, style: { marginTop: 8 } }, "Send reset code")), /* @__PURE__ */ import_react.default.createElement("p", { className: "dauth-footer-text" }, "Remember it?", " ", /* @__PURE__ */ import_react.default.createElement("a", { href: "/auth/login", className: "dauth-link" }, "Back to sign in"))));
106
+ };
107
+ var ResetPasswordScreen = ({
108
+ logo,
109
+ brandName = "Dravyn",
110
+ apiBase = process.env.NEXT_PUBLIC_AUTH_API_URL ?? "http://localhost:3001",
111
+ redirectTo = "/auth/login"
112
+ }) => {
113
+ const email = typeof sessionStorage !== "undefined" ? sessionStorage.getItem("dravyn_reset_email") ?? "" : "";
114
+ const [otp, setOtp] = import_react.default.useState(["", "", "", "", "", ""]);
115
+ const [password, setPassword] = import_react.default.useState("");
116
+ const [confirm, setConfirm] = import_react.default.useState("");
117
+ const [showPass, setShowPass] = import_react.default.useState(false);
118
+ const [loading, setLoading] = import_react.default.useState(false);
119
+ const [error, setError] = import_react.default.useState("");
120
+ const [done, setDone] = import_react.default.useState(false);
121
+ const inputRefs = import_react.default.useRef([]);
122
+ const handleOtpInput = (i, val) => {
123
+ if (val.length > 1) {
124
+ const digits = val.replace(/\D/g, "").slice(0, 6).split("");
125
+ const next2 = [...otp];
126
+ digits.forEach((d, idx) => {
127
+ if (idx < 6) next2[idx] = d;
128
+ });
129
+ setOtp(next2);
130
+ inputRefs.current[Math.min(digits.length, 5)]?.focus();
131
+ return;
132
+ }
133
+ const digit = val.replace(/\D/g, "");
134
+ const next = [...otp];
135
+ next[i] = digit;
136
+ setOtp(next);
137
+ if (digit && i < 5) inputRefs.current[i + 1]?.focus();
138
+ };
139
+ const handleSubmit = async (e) => {
140
+ e.preventDefault();
141
+ const code = otp.join("");
142
+ if (code.length < 6) {
143
+ setError("Enter the complete 6-digit code.");
144
+ return;
145
+ }
146
+ if (!password) {
147
+ setError("Enter a new password.");
148
+ return;
149
+ }
150
+ if (password.length < 8) {
151
+ setError("Password must be at least 8 characters.");
152
+ return;
153
+ }
154
+ if (password !== confirm) {
155
+ setError("Passwords do not match.");
156
+ return;
157
+ }
158
+ setLoading(true);
159
+ setError("");
160
+ try {
161
+ const res = await fetch(`${apiBase}/auth/reset-password`, {
162
+ method: "POST",
163
+ headers: { "Content-Type": "application/json" },
164
+ body: JSON.stringify({ email, otp: code, newPassword: password })
165
+ });
166
+ const data = await res.json();
167
+ if (!res.ok) {
168
+ setError(data.message ?? "Reset failed. Check the code and try again.");
169
+ return;
170
+ }
171
+ sessionStorage.removeItem("dravyn_reset_email");
172
+ setDone(true);
173
+ } catch {
174
+ setError("Unable to connect.");
175
+ } finally {
176
+ setLoading(false);
177
+ }
178
+ };
179
+ const EyeIcon = () => /* @__PURE__ */ import_react.default.createElement("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" }), /* @__PURE__ */ import_react.default.createElement("circle", { cx: "12", cy: "12", r: "3" }));
180
+ const EyeOffIcon = () => /* @__PURE__ */ import_react.default.createElement("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" }), /* @__PURE__ */ import_react.default.createElement("line", { x1: "2", x2: "22", y1: "2", y2: "22" }));
181
+ if (done) {
182
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-root" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-card" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-otp-icon", style: { color: "var(--dauth-green)" } }, "\u2713"), /* @__PURE__ */ import_react.default.createElement("h1", { className: "dauth-title" }, "Password reset!"), /* @__PURE__ */ import_react.default.createElement("p", { className: "dauth-sub" }, "Your password has been updated. You can now sign in."), /* @__PURE__ */ import_react.default.createElement(
183
+ import_ui.Button,
184
+ {
185
+ variant: "primary",
186
+ fullWidth: true,
187
+ style: { marginTop: 20 },
188
+ onClick: () => window.location.href = redirectTo
189
+ },
190
+ "Sign in"
191
+ )));
192
+ }
193
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-root" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-card" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-brand" }, logo ?? /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-logo-default" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "dauth-logo-dot" }), brandName)), /* @__PURE__ */ import_react.default.createElement("h1", { className: "dauth-title" }, "Set new password"), /* @__PURE__ */ import_react.default.createElement("p", { className: "dauth-sub" }, "Enter the code we sent you and choose a new password."), error && /* @__PURE__ */ import_react.default.createElement("div", { style: { marginBottom: 14 } }, /* @__PURE__ */ import_react.default.createElement(import_ui3.Alert, { variant: "danger" }, error)), /* @__PURE__ */ import_react.default.createElement("form", { onSubmit: handleSubmit, noValidate: true }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-fields" }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-label" }, "Reset code"), /* @__PURE__ */ import_react.default.createElement("div", { className: "dauth-otp-boxes", style: { marginTop: 6 } }, otp.map((d, i) => /* @__PURE__ */ import_react.default.createElement(
194
+ "input",
195
+ {
196
+ key: i,
197
+ ref: (el) => {
198
+ inputRefs.current[i] = el;
199
+ },
200
+ className: `dauth-otp-box ${d ? "dauth-otp-box--filled" : ""}`,
201
+ type: "text",
202
+ inputMode: "numeric",
203
+ maxLength: 6,
204
+ value: d,
205
+ onChange: (e) => handleOtpInput(i, e.target.value),
206
+ onKeyDown: (e) => {
207
+ if (e.key === "Backspace" && !d && i > 0) inputRefs.current[i - 1]?.focus();
208
+ },
209
+ "aria-label": `Digit ${i + 1}`
210
+ }
211
+ )))), /* @__PURE__ */ import_react.default.createElement(
212
+ import_ui2.Input,
213
+ {
214
+ label: "New password",
215
+ type: showPass ? "text" : "password",
216
+ placeholder: "Min. 8 characters",
217
+ value: password,
218
+ onChange: (e) => setPassword(e.target.value),
219
+ rightIcon: /* @__PURE__ */ import_react.default.createElement(
220
+ "button",
221
+ {
222
+ type: "button",
223
+ className: "dauth-eye",
224
+ onClick: () => setShowPass((v) => !v)
225
+ },
226
+ showPass ? /* @__PURE__ */ import_react.default.createElement(EyeOffIcon, null) : /* @__PURE__ */ import_react.default.createElement(EyeIcon, null)
227
+ )
228
+ }
229
+ ), /* @__PURE__ */ import_react.default.createElement(
230
+ import_ui2.Input,
231
+ {
232
+ label: "Confirm new password",
233
+ type: showPass ? "text" : "password",
234
+ placeholder: "Re-enter password",
235
+ value: confirm,
236
+ onChange: (e) => setConfirm(e.target.value)
237
+ }
238
+ )), /* @__PURE__ */ import_react.default.createElement(import_ui.Button, { type: "submit", variant: "primary", fullWidth: true, loading, style: { marginTop: 8 } }, "Reset password"))));
239
+ };
240
+ // Annotate the CommonJS export names for ESM import in node:
241
+ 0 && (module.exports = {
242
+ ForgotPasswordScreen,
243
+ ResetPasswordScreen
244
+ });
245
+ //# sourceMappingURL=ForgotResetScreen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/screens/ForgotResetScreen.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\nimport { Button } from '@dravyn/ui';\nimport { Input } from '@dravyn/ui';\nimport { Alert } from '@dravyn/ui';\nimport './auth.css';\n\n// ── ForgotPasswordScreen ──────────────────────────────────────────────────────\n\nexport interface ForgotPasswordScreenProps {\n logo?: React.ReactNode;\n brandName?: string;\n apiBase?: string;\n}\n\nexport const ForgotPasswordScreen: React.FC<ForgotPasswordScreenProps> = ({\n logo,\n brandName = 'Dravyn',\n apiBase = process.env.NEXT_PUBLIC_AUTH_API_URL ?? 'http://localhost:3001',\n}) => {\n const [email, setEmail] = React.useState('');\n const [loading, setLoading] = React.useState(false);\n const [error, setError] = React.useState('');\n const [sent, setSent] = React.useState(false);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!email.trim()) { setError('Email address is required.'); return; }\n if (!/\\S+@\\S+\\.\\S+/.test(email)) { setError('Enter a valid email address.'); return; }\n\n setLoading(true);\n setError('');\n try {\n const res = await fetch(`${apiBase}/auth/forgot-password`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: email.trim().toLowerCase() }),\n });\n // Always show success — don't reveal if email exists\n if (res.ok || res.status === 404) {\n sessionStorage.setItem('dravyn_reset_email', email.trim().toLowerCase());\n setSent(true);\n } else {\n const d = await res.json();\n setError(d.message ?? 'Something went wrong. Try again.');\n }\n } catch {\n setError('Unable to connect.');\n } finally {\n setLoading(false);\n }\n };\n\n if (sent) {\n return (\n <div className=\"dauth-root\">\n <div className=\"dauth-card\">\n <div className=\"dauth-brand\">\n {logo ?? <div className=\"dauth-logo-default\"><span className=\"dauth-logo-dot\" />{brandName}</div>}\n </div>\n <div className=\"dauth-otp-icon\">✓</div>\n <h1 className=\"dauth-title\">Check your inbox</h1>\n <p className=\"dauth-sub\">\n If <strong style={{ color: 'var(--dauth-text)' }}>{email}</strong> is\n registered, you'll receive a reset code shortly.\n </p>\n <Button\n variant=\"primary\"\n fullWidth\n style={{ marginTop: 20 }}\n onClick={() => window.location.href = '/auth/reset-password'}\n >\n Enter reset code\n </Button>\n <p className=\"dauth-footer-text\">\n <a href=\"/auth/login\" className=\"dauth-link\">Back to sign in</a>\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"dauth-root\">\n <div className=\"dauth-card\">\n <div className=\"dauth-brand\">\n {logo ?? <div className=\"dauth-logo-default\"><span className=\"dauth-logo-dot\" />{brandName}</div>}\n </div>\n\n <h1 className=\"dauth-title\">Reset your password</h1>\n <p className=\"dauth-sub\">\n Enter your email and we'll send you a reset code.\n </p>\n\n {error && <div style={{ marginBottom: 14 }}><Alert variant=\"danger\">{error}</Alert></div>}\n\n <form onSubmit={handleSubmit} noValidate>\n <div className=\"dauth-fields\">\n <Input\n label=\"Email address\"\n type=\"email\"\n placeholder=\"you@example.com\"\n value={email}\n onChange={e => setEmail(e.target.value)}\n autoComplete=\"email\"\n required\n />\n </div>\n <Button type=\"submit\" variant=\"primary\" fullWidth loading={loading} style={{ marginTop: 8 }}>\n Send reset code\n </Button>\n </form>\n\n <p className=\"dauth-footer-text\">\n Remember it?{' '}\n <a href=\"/auth/login\" className=\"dauth-link\">Back to sign in</a>\n </p>\n </div>\n </div>\n );\n};\n\n// ── ResetPasswordScreen ───────────────────────────────────────────────────────\n\nexport interface ResetPasswordScreenProps {\n logo?: React.ReactNode;\n brandName?: string;\n apiBase?: string;\n redirectTo?: string;\n}\n\nexport const ResetPasswordScreen: React.FC<ResetPasswordScreenProps> = ({\n logo,\n brandName = 'Dravyn',\n apiBase = process.env.NEXT_PUBLIC_AUTH_API_URL ?? 'http://localhost:3001',\n redirectTo = '/auth/login',\n}) => {\n const email = typeof sessionStorage !== 'undefined'\n ? sessionStorage.getItem('dravyn_reset_email') ?? '' : '';\n\n const [otp, setOtp] = React.useState(['', '', '', '', '', '']);\n const [password, setPassword] = React.useState('');\n const [confirm, setConfirm] = React.useState('');\n const [showPass, setShowPass] = React.useState(false);\n const [loading, setLoading] = React.useState(false);\n const [error, setError] = React.useState('');\n const [done, setDone] = React.useState(false);\n const inputRefs = React.useRef<(HTMLInputElement | null)[]>([]);\n\n const handleOtpInput = (i: number, val: string) => {\n if (val.length > 1) {\n const digits = val.replace(/\\D/g, '').slice(0, 6).split('');\n const next = [...otp];\n digits.forEach((d, idx) => { if (idx < 6) next[idx] = d; });\n setOtp(next);\n inputRefs.current[Math.min(digits.length, 5)]?.focus();\n return;\n }\n const digit = val.replace(/\\D/g, '');\n const next = [...otp]; next[i] = digit; setOtp(next);\n if (digit && i < 5) inputRefs.current[i + 1]?.focus();\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n const code = otp.join('');\n if (code.length < 6) { setError('Enter the complete 6-digit code.'); return; }\n if (!password) { setError('Enter a new password.'); return; }\n if (password.length < 8) { setError('Password must be at least 8 characters.'); return; }\n if (password !== confirm) { setError('Passwords do not match.'); return; }\n\n setLoading(true);\n setError('');\n try {\n const res = await fetch(`${apiBase}/auth/reset-password`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email, otp: code, newPassword: password }),\n });\n const data = await res.json();\n if (!res.ok) { setError(data.message ?? 'Reset failed. Check the code and try again.'); return; }\n sessionStorage.removeItem('dravyn_reset_email');\n setDone(true);\n } catch {\n setError('Unable to connect.');\n } finally {\n setLoading(false);\n }\n };\n\n const EyeIcon = () => <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/></svg>;\n const EyeOffIcon = () => <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M9.88 9.88a3 3 0 1 0 4.24 4.24\"/><path d=\"M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68\"/><path d=\"M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61\"/><line x1=\"2\" x2=\"22\" y1=\"2\" y2=\"22\"/></svg>;\n\n if (done) {\n return (\n <div className=\"dauth-root\">\n <div className=\"dauth-card\">\n <div className=\"dauth-otp-icon\" style={{ color: 'var(--dauth-green)' }}>✓</div>\n <h1 className=\"dauth-title\">Password reset!</h1>\n <p className=\"dauth-sub\">Your password has been updated. You can now sign in.</p>\n <Button variant=\"primary\" fullWidth style={{ marginTop: 20 }}\n onClick={() => window.location.href = redirectTo}>\n Sign in\n </Button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"dauth-root\">\n <div className=\"dauth-card\">\n <div className=\"dauth-brand\">\n {logo ?? <div className=\"dauth-logo-default\"><span className=\"dauth-logo-dot\" />{brandName}</div>}\n </div>\n\n <h1 className=\"dauth-title\">Set new password</h1>\n <p className=\"dauth-sub\">Enter the code we sent you and choose a new password.</p>\n\n {error && <div style={{ marginBottom: 14 }}><Alert variant=\"danger\">{error}</Alert></div>}\n\n <form onSubmit={handleSubmit} noValidate>\n {/* OTP row */}\n <div className=\"dauth-fields\">\n <div>\n <div className=\"dauth-label\">Reset code</div>\n <div className=\"dauth-otp-boxes\" style={{ marginTop: 6 }}>\n {otp.map((d, i) => (\n <input key={i}\n ref={el => { inputRefs.current[i] = el; }}\n className={`dauth-otp-box ${d ? 'dauth-otp-box--filled' : ''}`}\n type=\"text\" inputMode=\"numeric\" maxLength={6}\n value={d} onChange={e => handleOtpInput(i, e.target.value)}\n onKeyDown={e => { if (e.key === 'Backspace' && !d && i > 0) inputRefs.current[i-1]?.focus(); }}\n aria-label={`Digit ${i + 1}`}\n />\n ))}\n </div>\n </div>\n\n <Input\n label=\"New password\"\n type={showPass ? 'text' : 'password'}\n placeholder=\"Min. 8 characters\"\n value={password}\n onChange={e => setPassword(e.target.value)}\n rightIcon={\n <button type=\"button\" className=\"dauth-eye\"\n onClick={() => setShowPass(v => !v)}>\n {showPass ? <EyeOffIcon /> : <EyeIcon />}\n </button>\n }\n />\n <Input\n label=\"Confirm new password\"\n type={showPass ? 'text' : 'password'}\n placeholder=\"Re-enter password\"\n value={confirm}\n onChange={e => setConfirm(e.target.value)}\n />\n </div>\n\n <Button type=\"submit\" variant=\"primary\" fullWidth loading={loading} style={{ marginTop: 8 }}>\n Reset password\n </Button>\n </form>\n </div>\n </div>\n );\n};\n"],"mappings":"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","names":["import_ui","React","next"]}
@@ -0,0 +1,11 @@
1
+ "use client";
2
+ import {
3
+ ForgotPasswordScreen,
4
+ ResetPasswordScreen
5
+ } from "../chunk-FAI3ERB3.mjs";
6
+ import "../chunk-6BBGRN4E.mjs";
7
+ export {
8
+ ForgotPasswordScreen,
9
+ ResetPasswordScreen
10
+ };
11
+ //# sourceMappingURL=ForgotResetScreen.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,235 @@
1
+ /* src/screens/auth.css */
2
+ .dauth-root {
3
+ min-height: 100vh;
4
+ display: flex;
5
+ align-items: center;
6
+ justify-content: center;
7
+ background: var(--dui-bg, #0d0d0d);
8
+ padding: 24px 16px;
9
+ font-family: var(--dui-font-sans, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);
10
+ }
11
+ .dauth-card {
12
+ width: 100%;
13
+ max-width: 420px;
14
+ background: var(--dui-bg-raised, #161616);
15
+ border: 0.5px solid var(--dui-border-strong, rgba(255,255,255,0.16));
16
+ border-radius: 16px;
17
+ padding: 36px 32px 32px;
18
+ animation: dauth-in 220ms cubic-bezier(0.16, 1, 0.3, 1);
19
+ }
20
+ @keyframes dauth-in {
21
+ from {
22
+ opacity: 0;
23
+ transform: translateY(10px) scale(0.98);
24
+ }
25
+ to {
26
+ opacity: 1;
27
+ transform: translateY(0) scale(1);
28
+ }
29
+ }
30
+ .dauth-brand {
31
+ margin-bottom: 24px;
32
+ }
33
+ .dauth-logo-default {
34
+ display: inline-flex;
35
+ align-items: center;
36
+ gap: 7px;
37
+ font-size: 15px;
38
+ font-weight: 700;
39
+ color: var(--dui-text, #f0f0f0);
40
+ letter-spacing: -0.01em;
41
+ }
42
+ .dauth-logo-dot {
43
+ width: 8px;
44
+ height: 8px;
45
+ border-radius: 50%;
46
+ background: var(--dui-teal-400, #4ecdc4);
47
+ flex-shrink: 0;
48
+ }
49
+ .dauth-title {
50
+ font-size: 22px;
51
+ font-weight: 700;
52
+ color: var(--dui-text, #f0f0f0);
53
+ letter-spacing: -0.02em;
54
+ line-height: 1.2;
55
+ margin: 0 0 6px;
56
+ }
57
+ .dauth-sub {
58
+ font-size: 13.5px;
59
+ color: var(--dui-text-muted, #888);
60
+ line-height: 1.55;
61
+ margin: 0 0 22px;
62
+ }
63
+ .dauth-fields {
64
+ display: flex;
65
+ flex-direction: column;
66
+ gap: 14px;
67
+ margin-bottom: 14px;
68
+ }
69
+ .dauth-row {
70
+ display: grid;
71
+ grid-template-columns: 1fr 1fr;
72
+ gap: 10px;
73
+ }
74
+ .dauth-password-wrap {
75
+ display: flex;
76
+ flex-direction: column;
77
+ gap: 6px;
78
+ }
79
+ .dauth-forgot {
80
+ font-size: 12px;
81
+ color: var(--dui-text-muted, #888);
82
+ text-decoration: none;
83
+ align-self: flex-end;
84
+ transition: color 0.15s;
85
+ }
86
+ .dauth-forgot:hover {
87
+ color: var(--dui-teal-400, #4ecdc4);
88
+ }
89
+ .dauth-eye {
90
+ background: none;
91
+ border: none;
92
+ cursor: pointer;
93
+ color: var(--dui-text-hint, #555);
94
+ display: inline-flex;
95
+ align-items: center;
96
+ padding: 0;
97
+ transition: color 0.15s;
98
+ }
99
+ .dauth-eye:hover {
100
+ color: var(--dui-text-muted, #888);
101
+ }
102
+ .dauth-divider {
103
+ display: flex;
104
+ align-items: center;
105
+ gap: 10px;
106
+ margin: 18px 0;
107
+ color: var(--dui-text-hint, #555);
108
+ font-size: 12px;
109
+ }
110
+ .dauth-divider::before,
111
+ .dauth-divider::after {
112
+ content: "";
113
+ flex: 1;
114
+ height: 0.5px;
115
+ background: var(--dui-border, rgba(255,255,255,0.07));
116
+ }
117
+ .dauth-google-btn {
118
+ width: 100%;
119
+ display: flex;
120
+ align-items: center;
121
+ justify-content: center;
122
+ gap: 10px;
123
+ background: transparent;
124
+ border: 0.5px solid var(--dui-border-strong, rgba(255,255,255,0.16));
125
+ border-radius: 8px;
126
+ padding: 10px 18px;
127
+ font-family: var(--dui-font-sans);
128
+ font-size: 13px;
129
+ font-weight: 500;
130
+ color: var(--dui-text, #f0f0f0);
131
+ cursor: pointer;
132
+ transition: background 0.15s, border-color 0.15s;
133
+ }
134
+ .dauth-google-btn:hover:not(:disabled) {
135
+ background: var(--dui-bg-overlay, #1e1e1e);
136
+ border-color: rgba(255, 255, 255, 0.24);
137
+ }
138
+ .dauth-google-btn:disabled {
139
+ opacity: 0.4;
140
+ cursor: not-allowed;
141
+ }
142
+ .dauth-otp-icon {
143
+ font-size: 28px;
144
+ margin-bottom: 12px;
145
+ color: var(--dui-teal-400, #4ecdc4);
146
+ }
147
+ .dauth-otp-boxes {
148
+ display: flex;
149
+ gap: 8px;
150
+ justify-content: center;
151
+ margin: 20px 0 8px;
152
+ }
153
+ .dauth-otp-box {
154
+ width: 46px;
155
+ height: 54px;
156
+ background: var(--dui-bg, #0d0d0d);
157
+ border: 0.5px solid var(--dui-border-strong, rgba(255,255,255,0.16));
158
+ border-radius: 8px;
159
+ color: var(--dui-text, #f0f0f0);
160
+ font-size: 22px;
161
+ font-weight: 700;
162
+ font-family: var(--dui-font-sans);
163
+ text-align: center;
164
+ outline: none;
165
+ transition: border-color 0.15s, box-shadow 0.15s;
166
+ caret-color: var(--dui-teal-400, #4ecdc4);
167
+ }
168
+ .dauth-otp-box:focus {
169
+ border-color: var(--dui-teal-400, #4ecdc4);
170
+ box-shadow: 0 0 0 3px rgba(78, 205, 196, 0.12);
171
+ }
172
+ .dauth-otp-box--filled {
173
+ border-color: var(--dui-teal-400, #4ecdc4);
174
+ background: rgba(78, 205, 196, 0.04);
175
+ }
176
+ .dauth-resend {
177
+ text-align: center;
178
+ font-size: 13px;
179
+ color: var(--dui-text-muted, #888);
180
+ margin: 14px 0 4px;
181
+ }
182
+ .dauth-link {
183
+ color: var(--dui-teal-400, #4ecdc4);
184
+ text-decoration: none;
185
+ font-weight: 500;
186
+ background: none;
187
+ border: none;
188
+ cursor: pointer;
189
+ font-size: inherit;
190
+ font-family: inherit;
191
+ padding: 0;
192
+ transition: opacity 0.15s;
193
+ }
194
+ .dauth-link:hover {
195
+ opacity: 0.8;
196
+ }
197
+ .dauth-footer-text {
198
+ text-align: center;
199
+ font-size: 13px;
200
+ color: var(--dui-text-muted, #888);
201
+ margin-top: 18px;
202
+ }
203
+ .dauth-terms {
204
+ text-align: center;
205
+ font-size: 11.5px;
206
+ color: var(--dui-text-hint, #555);
207
+ margin-top: 12px;
208
+ line-height: 1.6;
209
+ }
210
+ :root {
211
+ --dauth-text: var(--dui-text, #f0f0f0);
212
+ --dauth-muted: var(--dui-text-muted, #888888);
213
+ --dauth-teal: var(--dui-teal-400, #4ecdc4);
214
+ --dauth-green: #22c55e;
215
+ --dauth-label: var(--dui-text-muted, #888888);
216
+ }
217
+ .dauth-label {
218
+ font-size: 12px;
219
+ font-weight: 500;
220
+ color: var(--dauth-label);
221
+ }
222
+ @media (max-width: 480px) {
223
+ .dauth-card {
224
+ padding: 28px 20px 24px;
225
+ }
226
+ .dauth-row {
227
+ grid-template-columns: 1fr;
228
+ }
229
+ .dauth-otp-box {
230
+ width: 40px;
231
+ height: 48px;
232
+ font-size: 20px;
233
+ }
234
+ }
235
+ /*# sourceMappingURL=LoginScreen.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/screens/auth.css"],"sourcesContent":["/*\n Dravyn Auth UI — Styles\n Consumes @dravyn/ui CSS custom properties.\n Import tokens first: import 'dravyn-ui/tokens'\n Then import this file once: import '@dravyn/auth-ui/auth.css'\n*/\n\n/* ── Root / centred layout ──────────────────────────────────────────────── */\n.dauth-root {\n min-height: 100vh;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--dui-bg, #0d0d0d);\n padding: 24px 16px;\n font-family: var(--dui-font-sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);\n}\n\n/* ── Card ───────────────────────────────────────────────────────────────── */\n.dauth-card {\n width: 100%;\n max-width: 420px;\n background: var(--dui-bg-raised, #161616);\n border: 0.5px solid var(--dui-border-strong, rgba(255,255,255,0.16));\n border-radius: 16px;\n padding: 36px 32px 32px;\n animation: dauth-in 220ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n@keyframes dauth-in {\n from { opacity: 0; transform: translateY(10px) scale(0.98); }\n to { opacity: 1; transform: translateY(0) scale(1); }\n}\n\n/* ── Brand / logo ───────────────────────────────────────────────────────── */\n.dauth-brand {\n margin-bottom: 24px;\n}\n\n.dauth-logo-default {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n font-size: 15px;\n font-weight: 700;\n color: var(--dui-text, #f0f0f0);\n letter-spacing: -0.01em;\n}\n\n.dauth-logo-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--dui-teal-400, #4ecdc4);\n flex-shrink: 0;\n}\n\n/* ── Headings ────────────────────────────────────────────────────────────── */\n.dauth-title {\n font-size: 22px;\n font-weight: 700;\n color: var(--dui-text, #f0f0f0);\n letter-spacing: -0.02em;\n line-height: 1.2;\n margin: 0 0 6px;\n}\n\n.dauth-sub {\n font-size: 13.5px;\n color: var(--dui-text-muted, #888);\n line-height: 1.55;\n margin: 0 0 22px;\n}\n\n/* ── Form fields ─────────────────────────────────────────────────────────── */\n.dauth-fields {\n display: flex;\n flex-direction: column;\n gap: 14px;\n margin-bottom: 14px;\n}\n\n.dauth-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n}\n\n/* ── Password wrap (holds input + forgot link) ───────────────────────────── */\n.dauth-password-wrap {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.dauth-forgot {\n font-size: 12px;\n color: var(--dui-text-muted, #888);\n text-decoration: none;\n align-self: flex-end;\n transition: color 0.15s;\n}\n\n.dauth-forgot:hover { color: var(--dui-teal-400, #4ecdc4); }\n\n/* ── Show/hide password button ───────────────────────────────────────────── */\n.dauth-eye {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--dui-text-hint, #555);\n display: inline-flex;\n align-items: center;\n padding: 0;\n transition: color 0.15s;\n}\n.dauth-eye:hover { color: var(--dui-text-muted, #888); }\n\n/* ── Divider ─────────────────────────────────────────────────────────────── */\n.dauth-divider {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 18px 0;\n color: var(--dui-text-hint, #555);\n font-size: 12px;\n}\n.dauth-divider::before,\n.dauth-divider::after {\n content: '';\n flex: 1;\n height: 0.5px;\n background: var(--dui-border, rgba(255,255,255,0.07));\n}\n\n/* ── Google OAuth button ─────────────────────────────────────────────────── */\n.dauth-google-btn {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n background: transparent;\n border: 0.5px solid var(--dui-border-strong, rgba(255,255,255,0.16));\n border-radius: 8px;\n padding: 10px 18px;\n font-family: var(--dui-font-sans);\n font-size: 13px;\n font-weight: 500;\n color: var(--dui-text, #f0f0f0);\n cursor: pointer;\n transition: background 0.15s, border-color 0.15s;\n}\n.dauth-google-btn:hover:not(:disabled) {\n background: var(--dui-bg-overlay, #1e1e1e);\n border-color: rgba(255,255,255,0.24);\n}\n.dauth-google-btn:disabled { opacity: 0.4; cursor: not-allowed; }\n\n/* ── OTP boxes ───────────────────────────────────────────────────────────── */\n.dauth-otp-icon {\n font-size: 28px;\n margin-bottom: 12px;\n color: var(--dui-teal-400, #4ecdc4);\n}\n\n.dauth-otp-boxes {\n display: flex;\n gap: 8px;\n justify-content: center;\n margin: 20px 0 8px;\n}\n\n.dauth-otp-box {\n width: 46px;\n height: 54px;\n background: var(--dui-bg, #0d0d0d);\n border: 0.5px solid var(--dui-border-strong, rgba(255,255,255,0.16));\n border-radius: 8px;\n color: var(--dui-text, #f0f0f0);\n font-size: 22px;\n font-weight: 700;\n font-family: var(--dui-font-sans);\n text-align: center;\n outline: none;\n transition: border-color 0.15s, box-shadow 0.15s;\n caret-color: var(--dui-teal-400, #4ecdc4);\n}\n\n.dauth-otp-box:focus {\n border-color: var(--dui-teal-400, #4ecdc4);\n box-shadow: 0 0 0 3px rgba(78, 205, 196, 0.12);\n}\n\n.dauth-otp-box--filled {\n border-color: var(--dui-teal-400, #4ecdc4);\n background: rgba(78, 205, 196, 0.04);\n}\n\n/* ── Resend row ──────────────────────────────────────────────────────────── */\n.dauth-resend {\n text-align: center;\n font-size: 13px;\n color: var(--dui-text-muted, #888);\n margin: 14px 0 4px;\n}\n\n/* ── Links ───────────────────────────────────────────────────────────────── */\n.dauth-link {\n color: var(--dui-teal-400, #4ecdc4);\n text-decoration: none;\n font-weight: 500;\n background: none;\n border: none;\n cursor: pointer;\n font-size: inherit;\n font-family: inherit;\n padding: 0;\n transition: opacity 0.15s;\n}\n.dauth-link:hover { opacity: 0.8; }\n\n/* ── Footer text + terms ─────────────────────────────────────────────────── */\n.dauth-footer-text {\n text-align: center;\n font-size: 13px;\n color: var(--dui-text-muted, #888);\n margin-top: 18px;\n}\n\n.dauth-terms {\n text-align: center;\n font-size: 11.5px;\n color: var(--dui-text-hint, #555);\n margin-top: 12px;\n line-height: 1.6;\n}\n\n/* ── CSS variable aliases (readable names inside auth components) ─────────── */\n:root {\n --dauth-text: var(--dui-text, #f0f0f0);\n --dauth-muted: var(--dui-text-muted, #888888);\n --dauth-teal: var(--dui-teal-400, #4ecdc4);\n --dauth-green: #22c55e;\n --dauth-label: var(--dui-text-muted, #888888);\n}\n\n/* ── Label helper (used in ResetPasswordScreen) ───────────────────────────── */\n.dauth-label {\n font-size: 12px;\n font-weight: 500;\n color: var(--dauth-label);\n}\n\n/* ── Responsive ──────────────────────────────────────────────────────────── */\n@media (max-width: 480px) {\n .dauth-card { padding: 28px 20px 24px; }\n .dauth-row { grid-template-columns: 1fr; }\n .dauth-otp-box { width: 40px; height: 48px; font-size: 20px; }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+
3
+ /**
4
+ * Dravyn Auth — LoginScreen
5
+ * Drop this into any Next.js / React project.
6
+ * Requires: @dravyn/ui (or dravyn-ui) and @dravyn/auth-js
7
+ *
8
+ * Usage (Next.js App Router):
9
+ * import { LoginScreen } from '@dravyn/auth-ui'
10
+ * export default function LoginPage() {
11
+ * return <LoginScreen redirectTo="/dashboard" />
12
+ * }
13
+ */
14
+
15
+ interface LoginScreenProps {
16
+ /** Where to send the user after a successful login */
17
+ redirectTo?: string;
18
+ /** Show / hide the "Create account" link */
19
+ showRegisterLink?: boolean;
20
+ /** Called with the JWT on success — use this OR redirectTo */
21
+ onSuccess?: (token: string, user: AuthUser) => void;
22
+ /** Override the logo node */
23
+ logo?: React.ReactNode;
24
+ /** Your brand name shown in the UI */
25
+ brandName?: string;
26
+ /** API base URL — defaults to NEXT_PUBLIC_AUTH_API_URL env var */
27
+ apiBase?: string;
28
+ }
29
+ interface AuthUser {
30
+ id: string;
31
+ email: string;
32
+ name: string;
33
+ }
34
+ declare const LoginScreen: React.FC<LoginScreenProps>;
35
+
36
+ export { LoginScreen, type LoginScreenProps };
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+
3
+ /**
4
+ * Dravyn Auth — LoginScreen
5
+ * Drop this into any Next.js / React project.
6
+ * Requires: @dravyn/ui (or dravyn-ui) and @dravyn/auth-js
7
+ *
8
+ * Usage (Next.js App Router):
9
+ * import { LoginScreen } from '@dravyn/auth-ui'
10
+ * export default function LoginPage() {
11
+ * return <LoginScreen redirectTo="/dashboard" />
12
+ * }
13
+ */
14
+
15
+ interface LoginScreenProps {
16
+ /** Where to send the user after a successful login */
17
+ redirectTo?: string;
18
+ /** Show / hide the "Create account" link */
19
+ showRegisterLink?: boolean;
20
+ /** Called with the JWT on success — use this OR redirectTo */
21
+ onSuccess?: (token: string, user: AuthUser) => void;
22
+ /** Override the logo node */
23
+ logo?: React.ReactNode;
24
+ /** Your brand name shown in the UI */
25
+ brandName?: string;
26
+ /** API base URL — defaults to NEXT_PUBLIC_AUTH_API_URL env var */
27
+ apiBase?: string;
28
+ }
29
+ interface AuthUser {
30
+ id: string;
31
+ email: string;
32
+ name: string;
33
+ }
34
+ declare const LoginScreen: React.FC<LoginScreenProps>;
35
+
36
+ export { LoginScreen, type LoginScreenProps };