@solid/react-component 0.1.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.
@@ -0,0 +1,924 @@
1
+ "use client";
2
+ "use strict";
3
+ "use client";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/login/next.tsx
23
+ var next_exports = {};
24
+ __export(next_exports, {
25
+ AuthGuard: () => AuthGuard,
26
+ SolidLoginNavigationProviderNext: () => SolidLoginNavigationProviderNext,
27
+ SolidLoginPage: () => SolidLoginPage
28
+ });
29
+ module.exports = __toCommonJS(next_exports);
30
+ var import_navigation = require("next/navigation");
31
+ var import_react5 = require("react");
32
+
33
+ // src/login/NavigationContext.tsx
34
+ var import_react = require("react");
35
+ var import_jsx_runtime = require("react/jsx-runtime");
36
+ var SolidLoginNavigationContext = (0, import_react.createContext)(null);
37
+ function SolidLoginNavigationProvider({
38
+ navigation,
39
+ config,
40
+ children
41
+ }) {
42
+ const fullConfig = {
43
+ loginPath: config?.loginPath ?? "/login",
44
+ homePath: config?.homePath ?? "/"
45
+ };
46
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SolidLoginNavigationContext.Provider, { value: { navigation, config: fullConfig }, children });
47
+ }
48
+ function useSolidLoginNavigation() {
49
+ return (0, import_react.useContext)(SolidLoginNavigationContext);
50
+ }
51
+
52
+ // src/login/AuthGuard.tsx
53
+ var import_react2 = require("react");
54
+ var import_solid_react = require("@ldo/solid-react");
55
+ var import_jsx_runtime2 = require("react/jsx-runtime");
56
+ var RETURN_TO_KEY = "solid-login-returnTo";
57
+ function storageGet(storage, key) {
58
+ try {
59
+ return storage.getItem(key);
60
+ } catch {
61
+ return null;
62
+ }
63
+ }
64
+ function storageSet(storage, key, value) {
65
+ try {
66
+ storage.setItem(key, value);
67
+ } catch {
68
+ }
69
+ }
70
+ function storageRemove(storage, key) {
71
+ try {
72
+ storage.removeItem(key);
73
+ } catch {
74
+ }
75
+ }
76
+ function isValidReturnPath(value) {
77
+ return typeof value === "string" && value.startsWith("/") && !value.startsWith("//");
78
+ }
79
+ function resolveReturnTo(searchParams, loginPath, homePath) {
80
+ const fromParam = searchParams.get("returnTo");
81
+ if (isValidReturnPath(fromParam)) return fromParam;
82
+ if (typeof window === "undefined") return homePath;
83
+ const fromStorage = storageGet(sessionStorage, RETURN_TO_KEY);
84
+ if (isValidReturnPath(fromStorage)) return fromStorage;
85
+ const browserPath = window.location.pathname;
86
+ if (browserPath !== loginPath && browserPath !== homePath && isValidReturnPath(browserPath)) {
87
+ return browserPath;
88
+ }
89
+ return homePath;
90
+ }
91
+ var defaultFallback = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
92
+ "div",
93
+ {
94
+ style: {
95
+ display: "flex",
96
+ minHeight: "100vh",
97
+ alignItems: "center",
98
+ justifyContent: "center",
99
+ background: "#fff"
100
+ },
101
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Loading..." })
102
+ }
103
+ );
104
+ function AuthGuardContent({
105
+ children,
106
+ fallback = defaultFallback
107
+ }) {
108
+ const { session, ranInitialAuthCheck = true } = (0, import_solid_react.useSolidAuth)();
109
+ const nav = useSolidLoginNavigation();
110
+ const pathname = nav?.navigation.getPathname() ?? "/";
111
+ const searchParams = nav?.navigation.getSearchParams() ?? { has: () => false, get: () => null };
112
+ const config = nav?.config ?? { loginPath: "/login", homePath: "/" };
113
+ const isOAuthCallback = searchParams.has("code") || searchParams.has("state");
114
+ const isLoginPage = pathname === config.loginPath;
115
+ const hasRedirectedRef = (0, import_react2.useRef)(false);
116
+ const prevPathnameRef = (0, import_react2.useRef)(pathname);
117
+ if (prevPathnameRef.current !== pathname) {
118
+ prevPathnameRef.current = pathname;
119
+ hasRedirectedRef.current = false;
120
+ }
121
+ (0, import_react2.useEffect)(() => {
122
+ if (typeof window === "undefined" || !isLoginPage || session.isLoggedIn) return;
123
+ const returnTo = searchParams.get("returnTo");
124
+ if (isValidReturnPath(returnTo)) {
125
+ storageSet(sessionStorage, RETURN_TO_KEY, returnTo);
126
+ }
127
+ }, [isLoginPage, session.isLoggedIn]);
128
+ (0, import_react2.useEffect)(() => {
129
+ if (!nav || !ranInitialAuthCheck || hasRedirectedRef.current) return;
130
+ const { navigation } = nav;
131
+ const sp = navigation.getSearchParams();
132
+ const path = navigation.getPathname();
133
+ const isCallback = sp.has("code") || sp.has("state");
134
+ const isLogin = path === config.loginPath;
135
+ if (isCallback && session.isLoggedIn) {
136
+ hasRedirectedRef.current = true;
137
+ let target = resolveReturnTo(sp, config.loginPath, config.homePath);
138
+ if (target === config.loginPath) target = config.homePath;
139
+ storageRemove(sessionStorage, RETURN_TO_KEY);
140
+ navigation.redirect(target);
141
+ return;
142
+ }
143
+ if (session.isLoggedIn && isLogin && !isCallback) {
144
+ hasRedirectedRef.current = true;
145
+ let target = resolveReturnTo(sp, config.loginPath, config.homePath);
146
+ if (target === config.loginPath) target = config.homePath;
147
+ storageRemove(sessionStorage, RETURN_TO_KEY);
148
+ navigation.replace(target);
149
+ return;
150
+ }
151
+ if (!session.isLoggedIn && !isLogin && !isCallback) {
152
+ hasRedirectedRef.current = true;
153
+ const current = path || "/";
154
+ if (current !== config.loginPath && current !== config.homePath) {
155
+ storageSet(sessionStorage, RETURN_TO_KEY, current);
156
+ }
157
+ const loginUrl = current === config.loginPath || current === config.homePath ? config.loginPath : `${config.loginPath}?returnTo=${encodeURIComponent(current)}`;
158
+ navigation.replace(loginUrl);
159
+ }
160
+ }, [ranInitialAuthCheck, session.isLoggedIn, pathname, nav, config.loginPath, config.homePath]);
161
+ if (!nav) {
162
+ if (process.env.NODE_ENV !== "production") {
163
+ console.warn(
164
+ "@solid/react-component: AuthGuard requires SolidLoginNavigationProvider (or use '@solid/react-component/login/next')"
165
+ );
166
+ }
167
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
168
+ }
169
+ if (!ranInitialAuthCheck) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: fallback });
170
+ if (isOAuthCallback) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: fallback });
171
+ if (!session.isLoggedIn && !isLoginPage) return null;
172
+ if (session.isLoggedIn && isLoginPage) return null;
173
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
174
+ }
175
+ function AuthGuard(props) {
176
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Suspense, { fallback: props.fallback ?? defaultFallback, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AuthGuardContent, { ...props }) });
177
+ }
178
+
179
+ // src/login/SolidLoginPage.tsx
180
+ var import_react4 = require("react");
181
+
182
+ // src/login/useSolidLogin.ts
183
+ var import_react3 = require("react");
184
+ var import_solid_react2 = require("@ldo/solid-react");
185
+ var DEFAULT_PRESETS = [
186
+ { label: "Solid Community", value: "https://solidcommunity.net/", secondaryLabel: "https://solidcommunity.net/" },
187
+ { label: "Inrupt", value: "https://login.inrupt.com", secondaryLabel: "https://login.inrupt.com" }
188
+ ];
189
+ function validateIssuerUrl(url) {
190
+ if (!url.trim()) return { valid: false, error: "Please enter a Solid Identity Provider URL" };
191
+ try {
192
+ const parsed = new URL(url);
193
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
194
+ return { valid: false, error: "URL must start with http:// or https://" };
195
+ }
196
+ } catch {
197
+ return { valid: false, error: "Please enter a valid URL" };
198
+ }
199
+ return { valid: true, error: null };
200
+ }
201
+ function useSolidLogin(options = {}) {
202
+ const { session, login } = (0, import_solid_react2.useSolidAuth)();
203
+ const [issuerInput, setIssuerInput] = (0, import_react3.useState)(options.defaultIssuer ?? "");
204
+ const [isLoading, setIsLoading] = (0, import_react3.useState)(false);
205
+ const [error, setError] = (0, import_react3.useState)(null);
206
+ const presetIssuers = options.presetIssuers ?? DEFAULT_PRESETS;
207
+ const validateAndSubmit = (0, import_react3.useCallback)(async () => {
208
+ const trimmed = issuerInput.trim();
209
+ const { valid, error: err } = validateIssuerUrl(trimmed);
210
+ if (!valid) {
211
+ setError(err);
212
+ return false;
213
+ }
214
+ setError(null);
215
+ setIsLoading(true);
216
+ try {
217
+ await login(trimmed, options.redirectUrl ? { redirectUrl: options.redirectUrl } : void 0);
218
+ return true;
219
+ } catch (e) {
220
+ console.error("Login failed:", e);
221
+ setIsLoading(false);
222
+ return false;
223
+ }
224
+ }, [issuerInput, login, options.redirectUrl]);
225
+ const setIssuer = (0, import_react3.useCallback)((value) => {
226
+ setIssuerInput(value);
227
+ setError(null);
228
+ }, []);
229
+ return {
230
+ session,
231
+ issuerInput,
232
+ setIssuerInput: setIssuer,
233
+ isLoading,
234
+ error,
235
+ presetIssuers,
236
+ validateAndSubmit,
237
+ login
238
+ };
239
+ }
240
+
241
+ // src/login/SolidLoginPage.tsx
242
+ var import_jsx_runtime3 = require("react/jsx-runtime");
243
+ var defaultTitle = "Sign in";
244
+ var defaultSubtitle = "to continue";
245
+ function ChevronDownIcon({
246
+ open,
247
+ style
248
+ }) {
249
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
250
+ "svg",
251
+ {
252
+ width: "20",
253
+ height: "20",
254
+ viewBox: "0 0 24 24",
255
+ fill: "none",
256
+ stroke: "currentColor",
257
+ strokeWidth: "2",
258
+ strokeLinecap: "round",
259
+ strokeLinejoin: "round",
260
+ style: {
261
+ transform: open ? "rotate(180deg)" : "rotate(0deg)",
262
+ transition: "transform 0.2s",
263
+ ...style
264
+ },
265
+ "aria-hidden": true,
266
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "m6 9 6 6 6-6" })
267
+ }
268
+ );
269
+ }
270
+ function GitHubIcon({ style }) {
271
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
272
+ "svg",
273
+ {
274
+ width: "16",
275
+ height: "16",
276
+ fill: "currentColor",
277
+ viewBox: "0 0 24 24",
278
+ "aria-hidden": true,
279
+ style,
280
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
281
+ "path",
282
+ {
283
+ fillRule: "evenodd",
284
+ d: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z",
285
+ clipRule: "evenodd"
286
+ }
287
+ )
288
+ }
289
+ );
290
+ }
291
+ function ReportIssueIcon({ style }) {
292
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
293
+ "svg",
294
+ {
295
+ width: "16",
296
+ height: "16",
297
+ fill: "none",
298
+ stroke: "currentColor",
299
+ viewBox: "0 0 24 24",
300
+ "aria-hidden": true,
301
+ style,
302
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
303
+ "path",
304
+ {
305
+ strokeLinecap: "round",
306
+ strokeLinejoin: "round",
307
+ strokeWidth: 2,
308
+ d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
309
+ }
310
+ )
311
+ }
312
+ );
313
+ }
314
+ function ButtonSpinner() {
315
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
316
+ "span",
317
+ {
318
+ style: {
319
+ display: "inline-block",
320
+ width: 14,
321
+ height: 14,
322
+ border: "2px solid transparent",
323
+ borderTopColor: "currentColor",
324
+ borderRadius: "50%",
325
+ animation: "solid-login-spin 0.6s linear infinite",
326
+ marginRight: 8,
327
+ verticalAlign: "middle"
328
+ }
329
+ }
330
+ );
331
+ }
332
+ function SolidLoginPage({
333
+ onAlreadyLoggedIn,
334
+ redirectUrl,
335
+ defaultIssuer,
336
+ presetIssuers,
337
+ logo,
338
+ logoAlt = "Logo",
339
+ title = defaultTitle,
340
+ subtitle = defaultSubtitle,
341
+ inputPlaceholder = "Enter your provider URL or select from the list",
342
+ inputLabel = "Solid Identity Provider",
343
+ buttonLabel = "Next",
344
+ buttonLoadingLabel = "Signing in...",
345
+ className = "",
346
+ footerGitHubUrl,
347
+ footerIssuesUrl,
348
+ renderLogo,
349
+ renderForm,
350
+ renderFooter
351
+ }) {
352
+ const {
353
+ session,
354
+ issuerInput,
355
+ setIssuerInput,
356
+ isLoading,
357
+ error,
358
+ presetIssuers: presets,
359
+ validateAndSubmit
360
+ } = useSolidLogin({ defaultIssuer, presetIssuers, redirectUrl });
361
+ const [showDropdown, setShowDropdown] = (0, import_react4.useState)(false);
362
+ const [highlightedIndex, setHighlightedIndex] = (0, import_react4.useState)(-1);
363
+ const inputRef = (0, import_react4.useRef)(null);
364
+ const dropdownRef = (0, import_react4.useRef)(null);
365
+ const generatedId = (0, import_react4.useId)();
366
+ const inputId = `solid-login-combobox-${generatedId}`;
367
+ const listboxId = `${inputId}-listbox`;
368
+ (0, import_react4.useEffect)(() => {
369
+ if (session.isLoggedIn && onAlreadyLoggedIn) onAlreadyLoggedIn();
370
+ }, [session.isLoggedIn, onAlreadyLoggedIn]);
371
+ (0, import_react4.useEffect)(() => {
372
+ const handleClickOutside = (e) => {
373
+ if (dropdownRef.current && !dropdownRef.current.contains(e.target) && inputRef.current && !inputRef.current.contains(e.target)) {
374
+ setShowDropdown(false);
375
+ }
376
+ };
377
+ if (showDropdown) {
378
+ document.addEventListener("mousedown", handleClickOutside);
379
+ return () => document.removeEventListener("mousedown", handleClickOutside);
380
+ }
381
+ }, [showDropdown]);
382
+ const filteredOptions = (0, import_react4.useMemo)(() => {
383
+ if (!issuerInput.trim()) return presets;
384
+ const q = issuerInput.toLowerCase();
385
+ return presets.filter(
386
+ (o) => o.label.toLowerCase().includes(q) || o.value.toLowerCase().includes(q) || o.secondaryLabel && o.secondaryLabel.toLowerCase().includes(q)
387
+ );
388
+ }, [issuerInput, presets]);
389
+ if (session.isLoggedIn) return null;
390
+ const handleSubmit = (e) => {
391
+ e.preventDefault();
392
+ validateAndSubmit();
393
+ };
394
+ const handleSelect = (option) => {
395
+ setIssuerInput(option.value);
396
+ setShowDropdown(false);
397
+ setHighlightedIndex(-1);
398
+ inputRef.current?.focus();
399
+ };
400
+ const handleKeyDown = (e) => {
401
+ if (!showDropdown) {
402
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
403
+ e.preventDefault();
404
+ setShowDropdown(true);
405
+ setHighlightedIndex(-1);
406
+ }
407
+ return;
408
+ }
409
+ switch (e.key) {
410
+ case "ArrowDown":
411
+ e.preventDefault();
412
+ setHighlightedIndex(
413
+ (prev) => prev < filteredOptions.length - 1 ? prev + 1 : prev
414
+ );
415
+ break;
416
+ case "ArrowUp":
417
+ e.preventDefault();
418
+ setHighlightedIndex((prev) => prev > 0 ? prev - 1 : prev);
419
+ break;
420
+ case "Enter":
421
+ if (highlightedIndex >= 0 && highlightedIndex < filteredOptions.length) {
422
+ e.preventDefault();
423
+ handleSelect(filteredOptions[highlightedIndex]);
424
+ }
425
+ break;
426
+ case "Escape":
427
+ e.preventDefault();
428
+ setShowDropdown(false);
429
+ setHighlightedIndex(-1);
430
+ break;
431
+ }
432
+ };
433
+ const formProps = {
434
+ issuerInput,
435
+ setIssuerInput,
436
+ error,
437
+ presetIssuers: presets,
438
+ isLoading,
439
+ onSubmit: handleSubmit,
440
+ onIssuerChange: setIssuerInput
441
+ };
442
+ if (renderForm) {
443
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
444
+ "main",
445
+ {
446
+ className,
447
+ role: "main",
448
+ "aria-label": "Sign in page",
449
+ style: { display: "flex", minHeight: "100vh", background: "#fff" },
450
+ children: renderForm(formProps)
451
+ }
452
+ );
453
+ }
454
+ const showFooter = renderFooter || footerGitHubUrl != null && footerIssuesUrl != null;
455
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
456
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("style", { children: `
457
+ @keyframes solid-login-spin {
458
+ to { transform: rotate(360deg); }
459
+ }
460
+ .solid-login-combobox-input:focus {
461
+ border-color: #7B42F6;
462
+ box-shadow: 0 0 0 1px #7B42F6;
463
+ }
464
+ @media (max-width: 1023px) {
465
+ .solid-login-left-panel { display: none !important; }
466
+ .solid-login-mobile-header { display: flex !important; }
467
+ }
468
+ @media (min-width: 1024px) {
469
+ .solid-login-mobile-header { display: none !important; }
470
+ }
471
+ @media (min-width: 1024px) {
472
+ .solid-login-right-panel { min-width: 450px; }
473
+ }
474
+ ` }),
475
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
476
+ "main",
477
+ {
478
+ className,
479
+ role: "main",
480
+ "aria-label": "Sign in page",
481
+ style: {
482
+ display: "flex",
483
+ flexDirection: "row",
484
+ flexWrap: "wrap",
485
+ minHeight: "100vh",
486
+ background: "#fff"
487
+ },
488
+ children: [
489
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
490
+ "section",
491
+ {
492
+ className: "solid-login-left-panel",
493
+ "aria-label": "Branding section",
494
+ style: {
495
+ display: "flex",
496
+ flex: "1 1 50%",
497
+ minWidth: 280,
498
+ alignItems: "center",
499
+ justifyContent: "center",
500
+ borderRight: "1px solid #e5e7eb",
501
+ background: "#F3EDFF",
502
+ padding: "2rem"
503
+ },
504
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { maxWidth: "28rem", width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
505
+ "header",
506
+ {
507
+ style: {
508
+ display: "flex",
509
+ flexDirection: "column",
510
+ alignItems: "center",
511
+ justifyContent: "center",
512
+ gap: 4
513
+ },
514
+ children: [
515
+ renderLogo ? renderLogo() : logo ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
516
+ "div",
517
+ {
518
+ style: {
519
+ width: 300,
520
+ height: 90,
521
+ display: "flex",
522
+ alignItems: "center",
523
+ justifyContent: "center"
524
+ },
525
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
526
+ "img",
527
+ {
528
+ src: logo,
529
+ alt: logoAlt,
530
+ style: { width: "100%", height: "100%", objectFit: "contain" }
531
+ }
532
+ )
533
+ }
534
+ ) : null,
535
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
536
+ "h1",
537
+ {
538
+ style: {
539
+ marginBottom: 2,
540
+ fontSize: "2.25rem",
541
+ fontWeight: 400,
542
+ color: "#000"
543
+ },
544
+ children: title
545
+ }
546
+ ),
547
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: { fontSize: "1rem", color: "#4b5563" }, children: subtitle })
548
+ ]
549
+ }
550
+ ) })
551
+ }
552
+ ),
553
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
554
+ "section",
555
+ {
556
+ className: "solid-login-right-panel",
557
+ "aria-label": "Sign in form section",
558
+ style: {
559
+ display: "flex",
560
+ flex: "1 1 50%",
561
+ flexDirection: "column",
562
+ alignItems: "center",
563
+ justifyContent: "center",
564
+ background: "#fff",
565
+ padding: "3rem 1rem",
566
+ minWidth: 0,
567
+ minHeight: 320
568
+ },
569
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { width: "100%", maxWidth: "28rem" }, children: [
570
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
571
+ "header",
572
+ {
573
+ className: "solid-login-mobile-header",
574
+ style: {
575
+ display: "none",
576
+ flexDirection: "column",
577
+ alignItems: "center",
578
+ justifyContent: "center",
579
+ marginBottom: "2rem"
580
+ },
581
+ children: [
582
+ renderLogo ? renderLogo() : logo ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
583
+ "div",
584
+ {
585
+ style: {
586
+ width: 300,
587
+ height: 90,
588
+ display: "flex",
589
+ alignItems: "center",
590
+ justifyContent: "center",
591
+ marginBottom: 8
592
+ },
593
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
594
+ "img",
595
+ {
596
+ src: logo,
597
+ alt: logoAlt,
598
+ style: { width: "100%", height: "100%", objectFit: "contain" }
599
+ }
600
+ )
601
+ }
602
+ ) : null,
603
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
604
+ "h1",
605
+ {
606
+ style: {
607
+ marginBottom: 8,
608
+ fontSize: "1.875rem",
609
+ fontWeight: 400,
610
+ color: "#000",
611
+ textAlign: "center"
612
+ },
613
+ children: title
614
+ }
615
+ ),
616
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: { fontSize: "1rem", color: "#4b5563", textAlign: "center" }, children: subtitle })
617
+ ]
618
+ }
619
+ ),
620
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
621
+ "form",
622
+ {
623
+ onSubmit: handleSubmit,
624
+ "aria-label": "Sign in form",
625
+ noValidate: true,
626
+ style: { display: "flex", flexDirection: "column", gap: "1.5rem" },
627
+ children: [
628
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
629
+ "label",
630
+ {
631
+ htmlFor: inputId,
632
+ style: {
633
+ display: "block",
634
+ marginBottom: 8,
635
+ fontSize: "0.875rem",
636
+ fontWeight: 500,
637
+ color: "#000"
638
+ },
639
+ children: inputLabel
640
+ }
641
+ ),
642
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { position: "relative" }, children: [
643
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
644
+ "input",
645
+ {
646
+ ref: inputRef,
647
+ id: inputId,
648
+ type: "text",
649
+ value: issuerInput,
650
+ onChange: (e) => setIssuerInput(e.target.value),
651
+ onFocus: () => {
652
+ setShowDropdown(true);
653
+ setHighlightedIndex(-1);
654
+ },
655
+ onKeyDown: handleKeyDown,
656
+ placeholder: inputPlaceholder,
657
+ disabled: isLoading,
658
+ "aria-invalid": !!error,
659
+ "aria-expanded": showDropdown,
660
+ "aria-controls": listboxId,
661
+ "aria-autocomplete": "list",
662
+ "aria-activedescendant": highlightedIndex >= 0 ? `${inputId}-option-${highlightedIndex}` : void 0,
663
+ role: "combobox",
664
+ autoComplete: "off",
665
+ className: "solid-login-combobox-input",
666
+ style: {
667
+ width: "100%",
668
+ height: 48,
669
+ paddingLeft: 16,
670
+ paddingRight: 40,
671
+ fontSize: "1rem",
672
+ color: "#000",
673
+ background: "#fff",
674
+ border: `1px solid ${error ? "#fca5a5" : "#d1d5db"}`,
675
+ borderRadius: 6,
676
+ outline: "none",
677
+ boxSizing: "border-box"
678
+ },
679
+ onBlur: () => {
680
+ }
681
+ }
682
+ ),
683
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
684
+ "button",
685
+ {
686
+ type: "button",
687
+ onClick: () => {
688
+ setShowDropdown(!showDropdown);
689
+ inputRef.current?.focus();
690
+ },
691
+ "aria-label": showDropdown ? "Hide options" : "Show options",
692
+ "aria-expanded": showDropdown,
693
+ tabIndex: -1,
694
+ style: {
695
+ position: "absolute",
696
+ right: 12,
697
+ top: "50%",
698
+ transform: "translateY(-50%)",
699
+ padding: 0,
700
+ border: "none",
701
+ background: "none",
702
+ cursor: "pointer",
703
+ color: "#9ca3af"
704
+ },
705
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronDownIcon, { open: showDropdown })
706
+ }
707
+ ),
708
+ showDropdown && filteredOptions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
709
+ "div",
710
+ {
711
+ ref: dropdownRef,
712
+ id: listboxId,
713
+ role: "listbox",
714
+ "aria-label": "Options",
715
+ style: {
716
+ position: "absolute",
717
+ zIndex: 10,
718
+ marginTop: 4,
719
+ width: "100%",
720
+ maxHeight: 240,
721
+ overflow: "auto",
722
+ border: "1px solid #e5e7eb",
723
+ borderRadius: 6,
724
+ background: "#fff",
725
+ boxShadow: "0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05)"
726
+ },
727
+ children: filteredOptions.map((option, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
728
+ "button",
729
+ {
730
+ id: `${inputId}-option-${index}`,
731
+ type: "button",
732
+ role: "option",
733
+ "aria-selected": issuerInput === option.value,
734
+ onClick: () => handleSelect(option),
735
+ onMouseEnter: () => setHighlightedIndex(index),
736
+ style: {
737
+ width: "100%",
738
+ padding: "12px 16px",
739
+ textAlign: "left",
740
+ border: "none",
741
+ background: highlightedIndex === index ? "#f3f4f6" : "transparent",
742
+ cursor: "pointer",
743
+ fontSize: "0.875rem",
744
+ color: "#111"
745
+ },
746
+ children: [
747
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontWeight: 500, marginBottom: 2 }, children: option.label }),
748
+ option.secondaryLabel && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
749
+ "div",
750
+ {
751
+ style: {
752
+ fontSize: "0.75rem",
753
+ color: "#6b7280",
754
+ overflow: "hidden",
755
+ textOverflow: "ellipsis",
756
+ whiteSpace: "nowrap"
757
+ },
758
+ children: option.secondaryLabel
759
+ }
760
+ )
761
+ ]
762
+ },
763
+ option.value
764
+ ))
765
+ }
766
+ )
767
+ ] }),
768
+ error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
769
+ "p",
770
+ {
771
+ role: "alert",
772
+ style: { fontSize: "0.75rem", color: "#dc2626", marginTop: 4 },
773
+ children: error
774
+ }
775
+ ),
776
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
777
+ "div",
778
+ {
779
+ style: {
780
+ display: "flex",
781
+ justifyContent: "flex-end",
782
+ paddingTop: 16
783
+ },
784
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
785
+ "button",
786
+ {
787
+ type: "submit",
788
+ disabled: isLoading,
789
+ "aria-busy": isLoading,
790
+ "aria-label": isLoading ? "Signing in, please wait" : "Continue to sign in",
791
+ style: {
792
+ padding: "8px 16px",
793
+ fontSize: "0.875rem",
794
+ fontWeight: 500,
795
+ color: "#fff",
796
+ background: isLoading ? "#d1d5db" : "#7B42F6",
797
+ border: "none",
798
+ borderRadius: 6,
799
+ cursor: isLoading ? "not-allowed" : "pointer",
800
+ display: "inline-flex",
801
+ alignItems: "center",
802
+ justifyContent: "center",
803
+ boxShadow: "none"
804
+ },
805
+ children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
806
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ButtonSpinner, {}),
807
+ buttonLoadingLabel
808
+ ] }) : buttonLabel
809
+ }
810
+ )
811
+ }
812
+ )
813
+ ]
814
+ }
815
+ ),
816
+ showFooter && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
817
+ "footer",
818
+ {
819
+ className: "solid-login-footer-wrap",
820
+ style: {
821
+ marginTop: "6rem",
822
+ display: "flex",
823
+ flexDirection: "column",
824
+ alignItems: "flex-end",
825
+ width: "100%"
826
+ },
827
+ children: renderFooter ? renderFooter() : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
828
+ "div",
829
+ {
830
+ style: {
831
+ display: "flex",
832
+ alignItems: "center",
833
+ gap: 16,
834
+ fontSize: "0.875rem",
835
+ color: "#6b7280"
836
+ },
837
+ children: [
838
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
839
+ "a",
840
+ {
841
+ href: footerGitHubUrl,
842
+ target: "_blank",
843
+ rel: "noopener noreferrer",
844
+ style: {
845
+ display: "inline-flex",
846
+ alignItems: "center",
847
+ gap: 6,
848
+ color: "inherit",
849
+ textDecoration: "none"
850
+ },
851
+ "aria-label": "View source code on GitHub",
852
+ children: [
853
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GitHubIcon, {}),
854
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "GitHub" })
855
+ ]
856
+ }
857
+ ),
858
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "#d1d5db" }, children: "\xB7" }),
859
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
860
+ "a",
861
+ {
862
+ href: footerIssuesUrl,
863
+ target: "_blank",
864
+ rel: "noopener noreferrer",
865
+ style: {
866
+ display: "inline-flex",
867
+ alignItems: "center",
868
+ gap: 6,
869
+ color: "inherit",
870
+ textDecoration: "none"
871
+ },
872
+ "aria-label": "Report an issue on GitHub",
873
+ children: [
874
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ReportIssueIcon, {}),
875
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Report an issue" })
876
+ ]
877
+ }
878
+ )
879
+ ]
880
+ }
881
+ )
882
+ }
883
+ )
884
+ ] })
885
+ }
886
+ )
887
+ ]
888
+ }
889
+ )
890
+ ] });
891
+ }
892
+
893
+ // src/login/next.tsx
894
+ var import_jsx_runtime4 = require("react/jsx-runtime");
895
+ function SolidLoginNavigationProviderNext({
896
+ config,
897
+ children
898
+ }) {
899
+ const router = (0, import_navigation.useRouter)();
900
+ const pathname = (0, import_navigation.usePathname)();
901
+ const searchParams = (0, import_navigation.useSearchParams)();
902
+ const navigation = (0, import_react5.useMemo)(
903
+ () => ({
904
+ getPathname: () => pathname ?? "/",
905
+ getSearchParams: () => ({
906
+ has: (key) => searchParams?.has(key) ?? false,
907
+ get: (key) => searchParams?.get(key) ?? null
908
+ }),
909
+ replace: (path) => router.replace(path),
910
+ redirect: (path) => {
911
+ if (typeof window !== "undefined") window.location.href = path;
912
+ }
913
+ }),
914
+ [router, pathname, searchParams]
915
+ );
916
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SolidLoginNavigationProvider, { navigation, config, children });
917
+ }
918
+ // Annotate the CommonJS export names for ESM import in node:
919
+ 0 && (module.exports = {
920
+ AuthGuard,
921
+ SolidLoginNavigationProviderNext,
922
+ SolidLoginPage
923
+ });
924
+ //# sourceMappingURL=next.cjs.map