@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.
package/README.md ADDED
@@ -0,0 +1,279 @@
1
+ # @solid/react-component
2
+
3
+ Reusable React components for Solid apps. One package that will grow to include login, profile, and other components—so you depend on a single library instead of many.
4
+
5
+ **Currently included:**
6
+
7
+ - **Login** – Solid OIDC login UI and auth guard. Two-column layout (branding + form), combobox-style provider picker, optional footer links. Next.js adapter included.
8
+
9
+ ---
10
+
11
+ ## Requirements
12
+
13
+ - **React** 18+
14
+ - **[@ldo/solid-react](https://www.npmjs.com/package/@ldo/solid-react)** – Your app must be wrapped in `BrowserSolidLdoProvider` (or `SolidLdoProvider`) so auth and session work.
15
+
16
+ For the **Next.js** login adapter you also need **Next.js 13+** (App Router).
17
+
18
+ ---
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm i @solid/react-component @ldo/solid-react react
24
+ ```
25
+
26
+ For Next.js apps:
27
+
28
+ ```bash
29
+ npm i @solid/react-component @ldo/solid-react next react
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Login – Next.js implementation
35
+
36
+ ### 1. Wrap the app with LDO’s provider
37
+
38
+ Your app must use `BrowserSolidLdoProvider` from `@ldo/solid-react` so session and login work.
39
+
40
+ ```tsx
41
+ // app/layout.tsx
42
+ import { BrowserSolidLdoProvider } from "@ldo/solid-react";
43
+
44
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
45
+ return (
46
+ <html lang="en">
47
+ <body>
48
+ <BrowserSolidLdoProvider>{children}</BrowserSolidLdoProvider>
49
+ </body>
50
+ </html>
51
+ );
52
+ }
53
+ ```
54
+
55
+ ### 2. Protect routes with the auth guard
56
+
57
+ Wrap the part of the tree that requires authentication in **Suspense**, **SolidLoginNavigationProviderNext**, and **AuthGuard**. Use the same config for both the home page and the login page.
58
+
59
+ **Config:**
60
+
61
+ - `loginPath` – Path to your login page (e.g. `"/login"`). Unauthenticated users are redirected here.
62
+ - `homePath` – Path after login when there is no `returnTo` (e.g. `"/"`).
63
+
64
+ ```tsx
65
+ // app/page.tsx (home or any protected page)
66
+ "use client";
67
+
68
+ import { Suspense } from "react";
69
+ import { SolidLoginNavigationProviderNext, AuthGuard } from "@solid/react-component/login/next";
70
+
71
+ const loadingFallback = (
72
+ <div style={{ display: "flex", minHeight: "100vh", alignItems: "center", justifyContent: "center" }}>
73
+ <span>Loading...</span>
74
+ </div>
75
+ );
76
+
77
+ export default function Home() {
78
+ return (
79
+ <Suspense fallback={loadingFallback}>
80
+ <SolidLoginNavigationProviderNext config={{ loginPath: "/login", homePath: "/" }}>
81
+ <AuthGuard fallback={loadingFallback}>
82
+ <YourMainApp />
83
+ </AuthGuard>
84
+ </SolidLoginNavigationProviderNext>
85
+ </Suspense>
86
+ );
87
+ }
88
+ ```
89
+
90
+ ### 3. Add the login page
91
+
92
+ Render **SolidLoginPage** on your login route. Pass the **logo** from your app (the package does not ship assets). You can also pass **footer** URLs so the default footer shows “GitHub” and “Report an issue” links.
93
+
94
+ ```tsx
95
+ // app/login/page.tsx
96
+ "use client";
97
+
98
+ import { Suspense } from "react";
99
+ import { useRouter } from "next/navigation";
100
+ import {
101
+ SolidLoginNavigationProviderNext,
102
+ AuthGuard,
103
+ SolidLoginPage,
104
+ } from "@solid/react-component/login/next";
105
+
106
+ const loadingFallback = (
107
+ <div style={{ display: "flex", minHeight: "100vh", alignItems: "center", justifyContent: "center" }}>
108
+ <span>Loading...</span>
109
+ </div>
110
+ );
111
+
112
+ export default function Login() {
113
+ const router = useRouter();
114
+
115
+ return (
116
+ <Suspense fallback={loadingFallback}>
117
+ <SolidLoginNavigationProviderNext config={{ loginPath: "/login", homePath: "/" }}>
118
+ <AuthGuard fallback={loadingFallback}>
119
+ <SolidLoginPage
120
+ onAlreadyLoggedIn={() => router.replace("/")}
121
+ logo="/your-logo.svg"
122
+ logoAlt="My App Logo"
123
+ title="Sign in"
124
+ subtitle="to continue to My App"
125
+ footerGitHubUrl="https://github.com/your-org/your-app"
126
+ footerIssuesUrl="https://github.com/your-org/your-app/issues/new"
127
+ />
128
+ </AuthGuard>
129
+ </SolidLoginNavigationProviderNext>
130
+ </Suspense>
131
+ );
132
+ }
133
+ ```
134
+
135
+ ### Custom redirect after login
136
+
137
+ By default, the IdP redirects back to the login page URL after authentication. If you want the user to land on a different page (e.g. your home page with a query param), pass `redirectUrl`:
138
+
139
+ ```tsx
140
+ <SolidLoginPage
141
+ redirectUrl={`${window.location.origin}/?showModal=true`}
142
+ onAlreadyLoggedIn={() => router.replace("/")}
143
+ logo="/logo.svg"
144
+ title="Sign in"
145
+ subtitle="to continue to My App"
146
+ />
147
+ ```
148
+
149
+ This tells the IdP to send the user straight to `/?showModal=true` instead of back to `/login`, avoiding a visible bounce through the login page.
150
+
151
+ ### 4. Next.js config (recommended)
152
+
153
+ If you use the package from npm, add it to `transpilePackages` so Next resolves the package’s subpath exports correctly:
154
+
155
+ ```ts
156
+ // next.config.ts
157
+ import type { NextConfig } from "next";
158
+
159
+ const nextConfig: NextConfig = {
160
+ transpilePackages: ["@solid/react-component"],
161
+ };
162
+
163
+ export default nextConfig;
164
+ ```
165
+
166
+ ---
167
+
168
+ ## How auth and redirects work
169
+
170
+ ### Session restore on refresh
171
+
172
+ The guard uses **LDO’s `ranInitialAuthCheck`** from `useSolidAuth()`. It shows the loading fallback until the initial auth check (including session restore from storage) has finished. Only then does it decide whether to redirect to login. So **refreshing while already logged in does not send you to the login page**; you stay on the same URL.
173
+
174
+ See [LDO useSolidAuth](https://ldo.js.org/1.0.0-alpha.X/api/solid-react/useSolidAuth/) for `ranInitialAuthCheck`.
175
+
176
+ ### returnTo (deep link back after login)
177
+
178
+ - When an unauthenticated user hits a protected path (e.g. `/dashboard/settings`), the guard redirects to `/login?returnTo=%2Fdashboard%2Fsettings`.
179
+ - After successful login (including after the OAuth redirect), the guard redirects to the `returnTo` path if it’s present and safe (starts with `/`, not `//`). If the IdP strips query params on callback, the package stores `returnTo` in `sessionStorage` when you land on the login page and uses it after the callback.
180
+ - If there is no valid `returnTo`, the user is sent to `homePath` (e.g. `"/"`).
181
+
182
+ ---
183
+
184
+ ## SolidLoginPage – props reference
185
+
186
+ | Prop | Type | Description |
187
+ |------|------|-------------|
188
+ | `onAlreadyLoggedIn` | `() => void` | Called when the user is already logged in (e.g. `() => router.replace("/")`). |
189
+ | `redirectUrl` | `string` | URL the IdP should redirect back to after authentication. Defaults to `window.location.href` (the login page). Useful when you want the IdP to send the user straight to a different page (e.g. `"/?showModal=true"`) instead of back to `/login`. |
190
+ | `logo` | `string` | **Required from your app.** URL to your logo image (e.g. `"/logo.svg"`). Not shipped in the package. |
191
+ | `logoAlt` | `string` | Alt text for the logo image. |
192
+ | `title` | `string` | Heading on the branding side (default: `"Sign in"`). |
193
+ | `subtitle` | `string` | Subheading (default: `"to continue"`). |
194
+ | `footerGitHubUrl` | `string` | If set with `footerIssuesUrl`, shows a footer with “GitHub” and “Report an issue” links. |
195
+ | `footerIssuesUrl` | `string` | See `footerGitHubUrl`. |
196
+ | `inputPlaceholder` | `string` | Placeholder for the provider URL input. |
197
+ | `inputLabel` | `string` | Label above the input (default: `"Solid Identity Provider"`). |
198
+ | `buttonLabel` | `string` | Submit button text (default: `"Next"`). |
199
+ | `buttonLoadingLabel` | `string` | Submit button text while logging in (default: `"Signing in..."`). |
200
+ | `defaultIssuer` | `string` | Pre-fill the issuer input. |
201
+ | `presetIssuers` | `PresetIssuer[]` | Options in the dropdown (default: Solid Community, Inrupt). |
202
+ | `className` | `string` | Extra class on the main container. |
203
+ | `renderLogo` | `() => ReactNode` | Replace the default logo block. |
204
+ | `renderForm` | `(props) => ReactNode` | Replace the entire form (see headless usage). |
205
+ | `renderFooter` | `() => ReactNode` | Replace the default footer. |
206
+
207
+ ---
208
+
209
+ ## Customizing the login page
210
+
211
+ - **Logo:** Pass `logo="/path/to/logo.svg"` from your app’s `public` (or asset URL). The package does not include assets.
212
+ - **Footer links:** Set `footerGitHubUrl` and `footerIssuesUrl` to show the default “GitHub” and “Report an issue” links. Or use `renderFooter` for a custom footer.
213
+ - **Full custom form:** Use `renderForm` and receive `{ issuerInput, setIssuerInput, error, presetIssuers, isLoading, onSubmit, onIssuerChange }` to build your own UI while keeping auth logic.
214
+
215
+ ---
216
+
217
+ ## Import paths
218
+
219
+ | Import from | Use for |
220
+ |-------------|--------|
221
+ | `@solid/react-component/login/next` | Next.js: `SolidLoginNavigationProviderNext`, `AuthGuard`, `SolidLoginPage`. Use in App Router pages. |
222
+ | `@solid/react-component/login` | Core login: `AuthGuard`, `SolidLoginPage`, `useSolidLogin`, `LoginFormControl`, etc. You provide navigation via `SolidLoginNavigationProvider`. |
223
+ | `@solid/react-component` | Barrel; re-exports from the login entry. Prefer subpaths above for clearer imports. |
224
+
225
+ ---
226
+
227
+ ## Headless login
228
+
229
+ If you want your own UI and only need the auth logic:
230
+
231
+ ```tsx
232
+ import { useSolidLogin, LoginFormControl, validateIssuerUrl } from "@solid/react-component/login";
233
+ ```
234
+
235
+ - **`useSolidLogin({ defaultIssuer, presetIssuers, onAlreadyLoggedIn, redirectUrl })`** – Returns `session`, `issuerInput`, `setIssuerInput`, `isLoading`, `error`, `presetIssuers`, `validateAndSubmit`.
236
+ - **`LoginFormControl`** – Render-prop component that provides the same state and handlers to children.
237
+ - **`validateIssuerUrl(url)`** – Returns `{ valid: boolean, error: string | null }`.
238
+
239
+ ---
240
+
241
+ ## AuthGuard – fallback
242
+
243
+ `AuthGuard` accepts an optional **`fallback`** prop (e.g. a loading spinner). It is shown:
244
+
245
+ - Until LDO’s initial auth check has run (`ranInitialAuthCheck`).
246
+ - During the OAuth callback (when the URL has `code` and `state`).
247
+
248
+ Use the same fallback in both your protected pages and the login page for a consistent loading state.
249
+
250
+ ---
251
+
252
+ ## Package structure
253
+
254
+ | Subpath | Contents |
255
+ |--------|----------|
256
+ | `@solid/react-component` | Re-exports (barrel). |
257
+ | `@solid/react-component/login` | Login: guard, page, hooks, types. |
258
+ | `@solid/react-component/login/next` | Login + Next.js adapter (provider + guard + page). |
259
+
260
+ Future components (e.g. profile) can follow the same pattern: `@solid/react-component/profile`, `@solid/react-component/profile/next`, etc.
261
+
262
+ ---
263
+
264
+ ## Building and publishing
265
+
266
+ From the package directory:
267
+
268
+ ```bash
269
+ npm run build
270
+ npm publish
271
+ ```
272
+
273
+ Unscoped packages are public by default. Bump `version` in `package.json` before each publish.
274
+
275
+ ---
276
+
277
+ ## License
278
+
279
+ MIT