Skip to content

Commit 1619793

Browse files
committed
v3 with middleware
1 parent a90ea88 commit 1619793

File tree

9 files changed

+7939
-7205
lines changed

9 files changed

+7939
-7205
lines changed

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,41 @@ export const action = () => {
4343

4444
## Setup
4545

46+
### Server-side (middleware mode)
47+
48+
In order to be able to show toasts anywhere in the app you need to add the following code to your `root.tsx` file.
49+
50+
```tsx
51+
import { getToast, unstable_toastMiddleware } from "remix-toast/middleware";
52+
53+
export const loader = async ({ request }: LoaderFunctionArgs) => {
54+
// Extracts the toast from the request
55+
const toast = getToast(context);
56+
// pass it to the client side
57+
return { toast }
58+
}
59+
60+
export default function App({ children }: { children: ReactNode }) {
61+
const { toast } = useLoaderData<typeof loader>();
62+
63+
useEffect(() => {
64+
if(toast){
65+
// Call your toast function here
66+
alert(toast.message);
67+
}
68+
}, [toast])
69+
70+
return (
71+
...
72+
);
73+
}
74+
75+
// Export the middleware to be used in the app
76+
export const unstable_middleware = [unstable_toastMiddleware()];
77+
78+
```
79+
80+
4681
### Server-side
4782

4883
In order to be able to show toasts anywhere in the app you need to add the following code to your `root.tsx` file.

package-lock.json

Lines changed: 7817 additions & 7171 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "remix-toast",
3-
"version": "2.0.0",
3+
"version": "3.0.0",
44
"description": "Utility functions for server-side toast notifications",
55
"type": "module",
66
"main": "./dist/index.cjs",
@@ -19,6 +19,20 @@
1919
"default": "./dist/index.cjs"
2020
},
2121
"types": "./dist/index.d.ts"
22+
},
23+
"./middleware": {
24+
"import": {
25+
"types": "./dist/middleware/index.d.ts",
26+
"default": "./dist/middleware/index.js",
27+
"import": "./dist/middleware/index.js"
28+
},
29+
"require": {
30+
"types": "./dist/middleware/index.d.cts",
31+
"import": "./dist/middleware/index.cjs",
32+
"require": "./dist/middleware/index.cjs",
33+
"default": "./dist/middleware/index.cjs"
34+
},
35+
"types": "./dist/middleware/index.d.ts"
2236
}
2337
},
2438
"typings": "./dist/index.d.ts",
@@ -30,8 +44,8 @@
3044
"."
3145
],
3246
"scripts": {
33-
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
34-
"dev-build": "tsup src/index.ts --format cjs,esm --dts --clean",
47+
"build": "tsup src/index.ts src/middleware/index.ts --format cjs,esm --dts --clean",
48+
"dev-build": "tsup src/index.ts src/middleware/index.ts --format cjs,esm --dts --clean",
3549
"react-router-dev": "npm run dev -w test-apps/react-router",
3650
"build:dev": "npm run dev-build",
3751
"build:dev:watch": "npm run dev-build -- --watch",
@@ -47,7 +61,7 @@
4761
"format-code": "npm run prettier:fix & npm run lint:fix"
4862
},
4963
"peerDependencies": {
50-
"react-router": ">=7.0.0"
64+
"react-router": ">=7.5.0"
5165
},
5266
"repository": {
5367
"type": "git",
@@ -81,7 +95,6 @@
8195
"happy-dom": "^9.5.0",
8296
"npm-run-all": "^4.1.5",
8397
"prettier": "^3.0.1",
84-
"react-router": "^7.0.1",
8598
"tsup": "^7.2.0",
8699
"typescript": "^5.0.4",
87100
"vite": "^4.2.1",

src/index.ts

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,14 @@
11
import {
2-
redirect,
3-
SessionStorage,
42
SessionIdStorageStrategy,
3+
type SessionStorage,
54
createCookieSessionStorage,
65
data as dataFn,
6+
redirect,
77
} from "react-router";
8-
import { FlashSessionValues, ToastMessage, flashSessionValuesSchema } from "./schema";
8+
import { type FlashSessionValues, type ToastMessage, flashSessionValuesSchema } from "./schema";
9+
import { type ToastCookieOptions, sessionStorage, toastCookieOptions } from "./session";
910

1011
const FLASH_SESSION = "flash";
11-
type ToastCookieOptions = Partial<SessionIdStorageStrategy["cookie"]>;
12-
13-
const toastCookieOptions = {
14-
name: "toast-session",
15-
sameSite: "lax",
16-
path: "/",
17-
httpOnly: true,
18-
secrets: ["s3Cr3t"],
19-
} satisfies ToastCookieOptions;
20-
21-
const sessionStorage = createCookieSessionStorage({
22-
cookie: toastCookieOptions,
23-
});
2412

2513
/**
2614
* Sets the cookie options to be used for the toast cookie

src/middleware/index.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import {
2+
type SessionStorage,
3+
type unstable_MiddlewareFunction,
4+
type unstable_RouterContextProvider,
5+
unstable_createContext,
6+
} from "react-router";
7+
import { type ToastMessage, getToast as getToastPrimitive } from "..";
8+
9+
const toastContext = unstable_createContext<ToastMessage | null>(null);
10+
11+
export function unstable_toastMiddleware(props?: { customSession?: SessionStorage }): unstable_MiddlewareFunction {
12+
const { customSession } = props || {};
13+
14+
return async function toastMiddleware({ request, context }, next) {
15+
const { toast, headers } = await getToastPrimitive(request, customSession);
16+
context.set(toastContext, toast ?? null);
17+
const res = await next();
18+
if (res instanceof Response && toast) {
19+
res.headers.append("Set-Cookie", headers.get("Set-Cookie") || "");
20+
}
21+
return res;
22+
};
23+
}
24+
25+
export const getToast = (context: unstable_RouterContextProvider) => context.get(toastContext);

src/session.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { type SessionIdStorageStrategy, createCookieSessionStorage } from "react-router";
2+
3+
export type ToastCookieOptions = Partial<SessionIdStorageStrategy["cookie"]>;
4+
5+
export const toastCookieOptions = {
6+
name: "toast-session",
7+
sameSite: "lax",
8+
path: "/",
9+
httpOnly: true,
10+
secrets: ["s3Cr3t"],
11+
} satisfies ToastCookieOptions;
12+
13+
export const sessionStorage = createCookieSessionStorage({
14+
cookie: toastCookieOptions,
15+
});

test-apps/react-router/app/root.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import { data, type LinksFunction, type LoaderFunctionArgs } from "react-router";
2-
import { Links, Meta, Outlet, Scripts, ScrollRestoration, useLoaderData } from "react-router";
31
import { useEffect } from "react";
2+
import { type LinksFunction, type LoaderFunctionArgs, data } from "react-router";
3+
import { Links, Meta, Outlet, Scripts, ScrollRestoration, useLoaderData } from "react-router";
44
import { ToastContainer, toast as notify } from "react-toastify";
55
import toastStyles from "react-toastify/ReactToastify.css?url";
6-
import { getToast } from "remix-toast";
6+
import { getToast, unstable_toastMiddleware } from "remix-toast/middleware";
77

88
export const links: LinksFunction = () => [{ rel: "stylesheet", href: toastStyles }];
99

10-
export const loader = async ({ request }: LoaderFunctionArgs) => {
11-
const { toast, headers } = await getToast(request);
12-
return data({ toast }, { headers });
10+
export const loader = async ({ request, context }: LoaderFunctionArgs) => {
11+
const toast = getToast(context);
12+
return { toast };
1313
};
1414

1515
export default function App() {
@@ -38,3 +38,5 @@ export default function App() {
3838
</html>
3939
);
4040
}
41+
42+
export const unstable_middleware = [unstable_toastMiddleware()];

test-apps/react-router/package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@
99
"typecheck": "react-router typegen && tsc --build --noEmit"
1010
},
1111
"dependencies": {
12-
"@react-router/node": "^7.0.1",
13-
"@react-router/serve": "^7.0.1",
12+
"@react-router/node": "^7.5.0",
13+
"@react-router/serve": "^7.5.0",
1414
"isbot": "^5.1.17",
1515
"react": "^18.3.1",
1616
"react-dom": "^18.3.1",
17-
"react-router": "^7.0.1",
17+
"react-router": "^7.5.0",
1818
"react-toastify": "^9.1.3",
1919
"remix-toast": "*"
2020
},
2121
"devDependencies": {
22-
"@react-router/dev": "^7.0.1",
23-
"@react-router/fs-routes": "^7.0.1",
22+
"@react-router/dev": "^7.5.0",
23+
"@react-router/fs-routes": "^7.5.0",
2424
"@types/node": "^20",
2525
"@types/react": "^18.3.12",
2626
"@types/react-dom": "^18.3.1",
@@ -30,6 +30,6 @@
3030
"typescript": "^5.6.3",
3131
"vite": "^5.4.11",
3232
"vite-tsconfig-paths": "^5.1.2",
33-
"react-router-devtools": "^1.0.1"
33+
"react-router-devtools": "^1.1.9"
3434
}
3535
}
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
import type { Config } from "@react-router/dev/config";
22

3-
export default {} satisfies Config;
3+
declare module "react-router" {
4+
interface Future {
5+
unstable_middleware: true; // 👈 Enable middleware types
6+
}
7+
}
8+
9+
export default {
10+
future: {
11+
unstable_middleware: true, // 👈 Enable middleware
12+
},
13+
} satisfies Config;

0 commit comments

Comments
 (0)