@passflow/react 0.15.0 → 0.16.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/CHANGELOG.md +47 -0
- package/README.md +60 -20
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +133 -146
- package/dist/index.es.js.map +1 -1
- package/dist/src/components/flow/index.d.cts +1 -1
- package/dist/src/components/flow/index.d.ts +1 -1
- package/dist/src/components/flow/index.d.ts.map +1 -1
- package/dist/src/components/flow/passflow/flow-router.d.cts +39 -0
- package/dist/src/components/flow/passflow/flow-router.d.ts +39 -0
- package/dist/src/components/flow/passflow/flow-router.d.ts.map +1 -0
- package/dist/src/components/flow/passflow/index.d.cts +25 -3
- package/dist/src/components/flow/passflow/index.d.ts +25 -3
- package/dist/src/components/flow/passflow/index.d.ts.map +1 -1
- package/dist/src/components/flow/two-factor-setup-magic-link/index.d.cts +6 -1
- package/dist/src/components/flow/two-factor-setup-magic-link/index.d.ts +6 -1
- package/dist/src/components/flow/two-factor-setup-magic-link/index.d.ts.map +1 -1
- package/dist/src/components/form/forgot-password/forgot-password-success.d.ts.map +1 -1
- package/dist/src/components/form/forgot-password/forgot-password.d.ts.map +1 -1
- package/dist/src/components/form/invitation-join/index.d.ts.map +1 -1
- package/dist/src/components/form/reset-password/index.d.ts.map +1 -1
- package/dist/src/components/form/signin/index.d.ts.map +1 -1
- package/dist/src/components/form/signup/index.d.ts.map +1 -1
- package/dist/src/components/form/two-factor-verify/two-factor-verify-form.d.ts.map +1 -1
- package/dist/src/components/form/verify-challenge/verify-challenge-magic-link.d.ts.map +1 -1
- package/dist/src/components/form/verify-challenge/verify-challenge-otp-manual.d.ts.map +1 -1
- package/dist/src/components/ui/fields/field-otp.d.cts +19 -6
- package/dist/src/components/ui/fields/field-otp.d.ts +19 -6
- package/dist/src/components/ui/fields/field-otp.d.ts.map +1 -1
- package/dist/src/components/ui/fields/field-password.d.ts.map +1 -1
- package/dist/src/components/ui/fields/field-phone.d.ts.map +1 -1
- package/dist/src/context/index.d.cts +1 -0
- package/dist/src/context/index.d.ts +1 -0
- package/dist/src/context/index.d.ts.map +1 -1
- package/dist/src/context/search-context.d.cts +20 -0
- package/dist/src/context/search-context.d.ts +20 -0
- package/dist/src/context/search-context.d.ts.map +1 -0
- package/dist/src/hooks/use-app-settings.d.ts.map +1 -1
- package/dist/src/utils/cn.d.ts.map +1 -1
- package/dist/src/utils/get-auth-methods.d.ts.map +1 -1
- package/dist/src/utils/get-form-labels.d.ts.map +1 -1
- package/dist/src/utils/url-params.d.cts +2 -4
- package/dist/src/utils/url-params.d.ts +2 -4
- package/dist/src/utils/url-params.d.ts.map +1 -1
- package/dist/src/utils/validation-schemas/index.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +9 -8
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@passflow/react` are documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.16.0] - 2026-11-03
|
|
6
|
+
|
|
7
|
+
### Breaking
|
|
8
|
+
|
|
9
|
+
- `react-router` is no longer a peer dependency, and the package does not import it. The only peers are `react` and `react-dom`, `^18 || ^19`. `PassflowFlow` keeps its own small router, so it works the same in an app that routes with React Router, TanStack Router, Wouter, another router, or none. A host that installed `react-router` only for this package can remove it.
|
|
10
|
+
- `PassflowFlow` no longer picks up a host React Router `<Router>`, and the console warning about `routerType` inside one is gone. Inside an app router in browser mode it shares the address bar with it: each side sees the other's navigations, and Back reaches both. Mount it on a catch-all route (`/auth/*` in React Router, `/auth/$` in TanStack Router, `<Route path="/auth" nest>` in Wouter).
|
|
11
|
+
- `pathPrefix` is an absolute path from the root of the URL. When it is not given, the flow takes it from the first URL it sees, so `<PassflowFlow />` on `/auth` or `/auth/signin` uses `/auth`. Before, inside a host router, it was relative to the parent route.
|
|
12
|
+
- `TwoFactorSetupMagicLinkFlow` no longer uses React Router's `useParams`. It reads the token from the URL segment after `/two-factor-setup-magic-link/`, or from a new `token` prop.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- `<PassflowFlow />` with no props works: browser history, prefix from the URL, every screen at a fixed path under it (`/signin`, `/signup`, `/verify-challenge-otp`, `/two-factor-setup-magic-link/:token`, …).
|
|
17
|
+
- Full control: pass `location` and `navigate` together and the app's router owns the location, for example a TanStack Router memory history. Their types are exported as `PassflowFlowLocation` and `PassflowFlowNavigate`.
|
|
18
|
+
- `PassflowFlow` serves the 2FA setup magic link (`/two-factor-setup-magic-link/:token`) as one of its screens.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Forms inside `PassflowFlow` read search params from the flow's location. In memory or hash mode, or under `location` + `navigate`, they read the address bar, which never carried them; forgot-password then threw "Invalid default method param".
|
|
23
|
+
|
|
24
|
+
### Internal
|
|
25
|
+
|
|
26
|
+
- Tests run the zero-config flow inside React Router, TanStack Router and Wouter (jsdom), and inside a TanStack Router app in Chromium. `@tanstack/react-router` and `wouter` are dev dependencies; `react-router` stays one, for those tests and the docs.
|
|
27
|
+
- The consumer type check installs no router.
|
|
28
|
+
|
|
29
|
+
## [0.15.1] - 2026-11-02
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- `PassflowFlow` navigates through its own router whatever the provider's `router` prop says. With the default value, every step inside the flow did a full page load through `window.location` to an unprefixed path, leaving a memory, hash or host router. Hosts that pass `router="react-router"` were not affected.
|
|
34
|
+
- A navigation asked for with `replace: true` inside `PassflowFlow` replaces the history entry. It pushed a new one, because `replace` was handed to React Router as part of the destination.
|
|
35
|
+
- The passwordless OTP screen and the 2FA verify form name the code field with a visible "Verification code" label. They used hidden text only, which fails WCAG labelling (axe `label-title-only`) once a wrong code shows an error.
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- `FieldOtp` takes an optional `label`: the field then draws its own visible label above the boxes. `labelledBy` still works; a field takes one or the other. New stories: With label, With label error.
|
|
40
|
+
- `PassflowProps`, the props of `PassflowFlow`, is exported from the package root.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- `lodash` and `tailwind-merge` are no longer dependencies. lodash is CommonJS, so it could not be tree-shaken and added about 70 KB minified to an app's bundle; tailwind-merge resolved Tailwind class conflicts in a library that styles only with `passflow-*` classes.
|
|
45
|
+
|
|
46
|
+
### Internal
|
|
47
|
+
|
|
48
|
+
- CI loads the packed package in plain Node through both `require` and `import`, and fails if either throws or the two expose different exports.
|
|
49
|
+
- README examples import from `@passflow/react` instead of the old package name.
|
|
50
|
+
- Two flaky UI tests fixed: the Storybook audits wait for the theme to settle, and the FieldOtp length test no longer depends on keystroke timing.
|
|
51
|
+
|
|
5
52
|
## [0.15.0] - 2026-11-02
|
|
6
53
|
|
|
7
54
|
### Breaking
|
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# @passflow/
|
|
1
|
+
# @passflow/react
|
|
2
2
|
|
|
3
3
|
This is a SDK for react application.
|
|
4
4
|
|
|
5
5
|
## Table of Contents
|
|
6
6
|
|
|
7
|
-
- [@passflow/
|
|
7
|
+
- [@passflow/react](#passflowreact)
|
|
8
8
|
- [Table of Contents](#table-of-contents)
|
|
9
9
|
- [Local Development](#local-development)
|
|
10
10
|
- [Using Local Passflow JS SDK](#using-local-passflow-js-sdk)
|
|
@@ -137,17 +137,15 @@ Both scripts automatically start the demo app and Storybook. `pnpm test` uses th
|
|
|
137
137
|
## Installation
|
|
138
138
|
|
|
139
139
|
```bash
|
|
140
|
-
pnpm add @passflow/react
|
|
140
|
+
pnpm add @passflow/react
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
No router is needed. `PassflowFlow` has its own small router, and works on its own or inside an app routed by React Router, TanStack Router, Wouter or anything else.
|
|
144
144
|
|
|
145
145
|
## Requirements
|
|
146
146
|
|
|
147
|
-
- React 18
|
|
148
|
-
- React Router 7 or 8 (React Router 6 is not supported)
|
|
147
|
+
- React 18 or 19
|
|
149
148
|
- Node `^22.12.0 || ^24.0.0 || >=26.0.0`
|
|
150
|
-
- Your app may route with React Router, Wouter or TanStack Router
|
|
151
149
|
|
|
152
150
|
## Integration
|
|
153
151
|
|
|
@@ -246,21 +244,63 @@ authentication-context claims those tokens carry.
|
|
|
246
244
|
|
|
247
245
|
### PassflowFlow
|
|
248
246
|
|
|
247
|
+
The whole sign-in experience on its own pages: sign-in, sign-up, one-time codes, magic links, password reset, invitations and two-factor. It needs no router and no setup:
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
<PassflowProvider url="https://auth.example.com" appId="your-app-id">
|
|
251
|
+
<PassflowFlow />
|
|
252
|
+
</PassflowProvider>
|
|
253
|
+
```
|
|
254
|
+
|
|
249
255
|
| Prop | Type | Description |
|
|
250
256
|
|------|------|-------------|
|
|
251
257
|
| successAuthRedirect | string | URL to redirect after successful authentication |
|
|
252
|
-
| federatedDisplayMode | "
|
|
253
|
-
| pathPrefix | string |
|
|
258
|
+
| federatedDisplayMode | "modal" \| "redirect" | Federated authentication display mode |
|
|
259
|
+
| pathPrefix | string | Where the flow lives, such as `/auth`. Optional: worked out from the first URL |
|
|
260
|
+
| routerType | "browser" \| "hash" \| "memory" | The history the flow keeps. Default `browser` |
|
|
261
|
+
| location, navigate | see below | Full control by the app's router. Optional, always together |
|
|
262
|
+
|
|
263
|
+
**Paths.** The flow's screens are `<prefix>/signin`, `<prefix>/signup`, `<prefix>/verify-challenge-otp`, `<prefix>/verify-challenge-magic-link`, `<prefix>/forgot-password`, `<prefix>/forgot-password/success`, `<prefix>/password/reset`, `<prefix>/invitation`, `<prefix>/two-factor-verify`, `<prefix>/two-factor-setup` and `<prefix>/two-factor-setup-magic-link/:token`. Without `pathPrefix` the flow takes the prefix from the first URL it sees: `/auth/signin` and `/auth` both give `/auth`, `/` gives none. A path under the prefix that names no screen goes to sign-in.
|
|
264
|
+
|
|
265
|
+
**Inside an app's router.** Mount the flow on a catch-all route; nothing else is needed. The flow moves the address bar and announces it with `popstate`, the event React Router, TanStack Router and Wouter listen to, so the app's router follows the flow and the flow follows the app, Back and Forward included:
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
// TanStack Router
|
|
269
|
+
const authRoute = createRoute({ getParentRoute: () => rootRoute, path: '/auth/$', component: () => <PassflowFlow /> });
|
|
270
|
+
|
|
271
|
+
// React Router
|
|
272
|
+
<Route path="/auth/*" element={<PassflowFlow />} />
|
|
254
273
|
|
|
255
|
-
|
|
274
|
+
// Wouter
|
|
275
|
+
<Route path="/auth" nest><PassflowFlow /></Route>
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**`routerType`.** `browser` (default) uses the address bar. `hash` keeps the flow's path after `#`. `memory` leaves the URL alone, for an embedded widget or tests.
|
|
279
|
+
|
|
280
|
+
**Full control.** When the app's router does not use the address bar (it runs in hash or memory mode), hand the flow its location and a way to move it. `routerType` is then not used:
|
|
256
281
|
|
|
257
282
|
```tsx
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
283
|
+
// TanStack Router with a memory or hash history
|
|
284
|
+
function AuthPage() {
|
|
285
|
+
const router = useRouter();
|
|
286
|
+
const location = useRouterState({ select: (state) => state.location });
|
|
287
|
+
return (
|
|
288
|
+
<PassflowFlow
|
|
289
|
+
location={{ pathname: location.pathname, search: location.searchStr }}
|
|
290
|
+
navigate={(to, { replace }) => {
|
|
291
|
+
const href = `${to.pathname}${to.search}`;
|
|
292
|
+
if (replace) router.history.replace(href);
|
|
293
|
+
else router.history.push(href);
|
|
294
|
+
}}
|
|
295
|
+
/>
|
|
296
|
+
);
|
|
297
|
+
}
|
|
262
298
|
```
|
|
263
299
|
|
|
300
|
+
`TwoFactorSetupMagicLinkFlow` can also be mounted on its own page. It reads the token from the URL (the segment after `/two-factor-setup-magic-link/`), or takes it as a `token` prop.
|
|
301
|
+
|
|
302
|
+
The sections below wire the app's router into the **standalone form components** (`SignIn`, `SignUp`, …) through `PassflowProvider`'s `navigate` and `router` props. `PassflowFlow` does not need them.
|
|
303
|
+
|
|
264
304
|
### React Router
|
|
265
305
|
|
|
266
306
|
Example of integration with React Router:
|
|
@@ -273,7 +313,7 @@ import {
|
|
|
273
313
|
SignUp,
|
|
274
314
|
ForgotPassword,
|
|
275
315
|
ForgotPasswordSuccess,
|
|
276
|
-
} from "@passflow/
|
|
316
|
+
} from "@passflow/react";
|
|
277
317
|
import { BrowserRouter, Routes, Route, useNavigate } from "react-router";
|
|
278
318
|
|
|
279
319
|
const passflowConfig = {
|
|
@@ -344,7 +384,7 @@ import {
|
|
|
344
384
|
SignUp,
|
|
345
385
|
ForgotPassword,
|
|
346
386
|
ForgotPasswordSuccess,
|
|
347
|
-
} from "@passflow/
|
|
387
|
+
} from "@passflow/react";
|
|
348
388
|
import { Switch, Route, useLocation } from "wouter";
|
|
349
389
|
|
|
350
390
|
const passflowConfig = {
|
|
@@ -410,7 +450,7 @@ export const App = () => (
|
|
|
410
450
|
);
|
|
411
451
|
|
|
412
452
|
// PassflowProviderWrapper.tsx
|
|
413
|
-
import { PassflowProvider } from '@passflow/
|
|
453
|
+
import { PassflowProvider } from '@passflow/react';
|
|
414
454
|
|
|
415
455
|
const passflowConfig = {
|
|
416
456
|
url: import.meta.env.VITE_PASSFLOW_URL,
|
|
@@ -432,7 +472,7 @@ export const PassflowProviderWrapper = ({ children }) => (
|
|
|
432
472
|
);
|
|
433
473
|
|
|
434
474
|
// router/root.tsx
|
|
435
|
-
import { useNavigation } from '@passflow/
|
|
475
|
+
import { useNavigation } from '@passflow/react';
|
|
436
476
|
import { Outlet, useNavigate } from '@tanstack/react-router';
|
|
437
477
|
|
|
438
478
|
export const Root = () => {
|
|
@@ -451,7 +491,7 @@ import { QueryClient } from '@tanstack/react-query';
|
|
|
451
491
|
import { createRouter } from '@tanstack/react-router';
|
|
452
492
|
import { queryClient } from '../query';
|
|
453
493
|
import { routerTree } from './routes';
|
|
454
|
-
import { Passflow } from '@passflow/
|
|
494
|
+
import { Passflow } from '@passflow/react';
|
|
455
495
|
|
|
456
496
|
export interface RouterContext {
|
|
457
497
|
queryClient: QueryClient;
|
|
@@ -479,7 +519,7 @@ import { Outlet, createRootRouteWithContext, createRoute, redirect } from '@tans
|
|
|
479
519
|
import { RouterContext } from './router';
|
|
480
520
|
import { Root } from './root';
|
|
481
521
|
import { About, Home } from '@/pages';
|
|
482
|
-
import { ForgotPassword, ForgotPasswordSuccess, SignIn, SignUp } from '@passflow/
|
|
522
|
+
import { ForgotPassword, ForgotPasswordSuccess, SignIn, SignUp } from '@passflow/react';
|
|
483
523
|
import { RootLayout } from '@/layouts';
|
|
484
524
|
|
|
485
525
|
const redirectToSignin = () => {
|