From 47e55ed6cd7467196059a784f859601e93df7c17 Mon Sep 17 00:00:00 2001
From: Pedro Ferreira <10789765+apedroferreira@users.noreply.github.com>
Date: Tue, 7 Jan 2025 12:44:26 +0000
Subject: [PATCH] [AppProvider] Use unique names for framework specific
`AppProvider`s (#4553)
---
.../components/app-provider/app-provider.md | 26 +++++-----
.../toolpad/core/integrations/ReactRouter.js | 8 ++--
.../toolpad/core/integrations/ReactRouter.tsx | 8 ++--
.../core/integrations/nextjs-approuter.md | 12 ++---
.../core/integrations/nextjs-pagesrouter.md | 16 +++----
.../toolpad/core/integrations/react-router.md | 42 ++++++++---------
.../core/introduction/base-concepts.md | 4 +-
docs/package.json | 2 +-
docs/pages/toolpad/core/api/app-provider.json | 2 +-
.../core/auth-nextjs-email/src/app/layout.tsx | 6 +--
.../src/pages/_app.tsx | 6 +--
.../core/auth-nextjs-pages/src/pages/_app.tsx | 6 +--
.../auth-nextjs-passkey/src/app/layout.tsx | 6 +--
.../core/auth-nextjs-themed/app/layout.tsx | 6 +--
examples/core/auth-nextjs/src/app/layout.tsx | 6 +--
examples/core/auth-vite/package.json | 2 +-
examples/core/auth-vite/src/App.tsx | 10 ++--
.../core/auth-vite/src/layouts/dashboard.tsx | 2 +-
examples/core/auth-vite/src/main.tsx | 2 +-
examples/core/auth-vite/src/pages/signIn.tsx | 2 +-
examples/core/firebase-vite/package.json | 2 +-
examples/core/firebase-vite/src/App.tsx | 8 ++--
.../firebase-vite/src/layouts/dashboard.tsx | 2 +-
examples/core/firebase-vite/src/main.tsx | 2 +-
.../core/firebase-vite/src/pages/signin.tsx | 2 +-
examples/core/tutorial/app/layout.tsx | 6 +--
examples/core/vite/package.json | 2 +-
examples/core/vite/src/App.tsx | 9 ++--
examples/core/vite/src/layouts/dashboard.tsx | 2 +-
examples/core/vite/src/main.tsx | 2 +-
.../src/templates/nextjs-app/rootLayout.ts | 6 +--
.../src/templates/nextjs-pages/app.ts | 6 +--
packages/toolpad-core/package.json | 6 +--
.../toolpad-core/src/nextjs/AppProvider.tsx | 17 -------
...ider.test.tsx => NextAppProvider.test.tsx} | 4 +-
.../src/nextjs/NextAppProvider.tsx | 19 ++++++++
...iderNextApp.tsx => NextAppProviderApp.tsx} | 2 +-
...NextPages.tsx => NextAppProviderPages.tsx} | 2 +-
packages/toolpad-core/src/nextjs/index.tsx | 2 +-
.../src/react-router-dom/index.tsx | 1 -
.../ReactRouterAppProvider.test.tsx} | 6 +--
.../ReactRouterAppProvider.tsx} | 23 ++++-----
.../toolpad-core/src/react-router/index.tsx | 1 +
packages/toolpad-studio/package.json | 2 +-
.../toolpad-studio/src/runtime/AppLayout.tsx | 8 ++--
.../src/runtime/PreviewHeader.tsx | 2 +-
.../toolpad-studio/src/runtime/SignInPage.tsx | 2 +-
.../toolpad-studio/src/runtime/ToolpadApp.tsx | 2 +-
.../toolpad-studio/src/runtime/useAuth.ts | 2 +-
.../src/toolpad/AppEditor/index.tsx | 2 +-
.../toolpad-studio/src/toolpad/AppState.tsx | 2 +-
.../toolpad-studio/src/toolpad/Toolpad.tsx | 2 +-
.../ToolpadShell/ToolpadNavigation.tsx | 2 +-
packages/toolpad-studio/src/utils/domView.ts | 2 +-
playground/nextjs-pages/src/pages/_app.tsx | 6 +--
playground/nextjs/src/app/layout.tsx | 6 +--
playground/vite/package.json | 2 +-
playground/vite/src/App.tsx | 9 ++--
playground/vite/src/layouts/dashboard.tsx | 2 +-
playground/vite/src/main.tsx | 2 +-
pnpm-lock.yaml | 47 ++++++++++++++-----
.../config/getComponentImports.ts | 20 +++++---
.../config/projectSettings.ts | 2 +-
63 files changed, 232 insertions(+), 198 deletions(-)
delete mode 100644 packages/toolpad-core/src/nextjs/AppProvider.tsx
rename packages/toolpad-core/src/nextjs/{AppProvider.test.tsx => NextAppProvider.test.tsx} (90%)
create mode 100644 packages/toolpad-core/src/nextjs/NextAppProvider.tsx
rename packages/toolpad-core/src/nextjs/{AppProviderNextApp.tsx => NextAppProviderApp.tsx} (93%)
rename packages/toolpad-core/src/nextjs/{AppProviderNextPages.tsx => NextAppProviderPages.tsx} (95%)
delete mode 100644 packages/toolpad-core/src/react-router-dom/index.tsx
rename packages/toolpad-core/src/{react-router-dom/AppProvider.test.tsx => react-router/ReactRouterAppProvider.test.tsx} (70%)
rename packages/toolpad-core/src/{react-router-dom/AppProvider.tsx => react-router/ReactRouterAppProvider.tsx} (65%)
create mode 100644 packages/toolpad-core/src/react-router/index.tsx
diff --git a/docs/data/toolpad/core/components/app-provider/app-provider.md b/docs/data/toolpad/core/components/app-provider/app-provider.md
index 20e2d4129e5..29e14a55308 100644
--- a/docs/data/toolpad/core/components/app-provider/app-provider.md
+++ b/docs/data/toolpad/core/components/app-provider/app-provider.md
@@ -26,22 +26,22 @@ In the following example, an `AppProvider` component wrapping the page provides
## Next.js
-The `AppProvider` for Next.js applications includes some Next.js integrations out-of-the-box.
+The `NextAppProvider` includes some Next.js integrations out-of-the-box.
-By using the specific `AppProvider` for Next.js you do not have to manually configure the integration between some Toolpad features and the corresponding Next.js features (such as routing), making the integration automatic and seamless.
+By using the specific `NextAppProvider` you do not have to manually configure the integration between some Toolpad features and the corresponding Next.js features (such as routing), making the integration automatic and seamless.
```tsx
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
```
### Next.js App Router
-When using the **Next.js App Router**, the most typical file where to import and use `AppProvider` will be at the top level `layout.tsx` file that defines the layout for all the application pages.
+When using the **Next.js App Router**, the most typical file where to import and use `NextAppProvider` is the top level `layout.tsx` file that defines the layout for all the application pages.
```tsx
// app/layout.tsx
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
export default function Layout(props) {
const { children } = props;
@@ -49,7 +49,7 @@ export default function Layout(props) {
return (
- {children}
+ {children}
);
@@ -58,32 +58,32 @@ export default function Layout(props) {
### Next.js Pages Router
-When using the **Next.js Pages Router**, the most typical file where to import and use `AppProvider` in order to wrap every page in the application will be the `pages/_app.tsx` file.
+When using the **Next.js Pages Router**, the most typical file where to import and use `NextAppProvider` in order to wrap every page in the application is the `pages/_app.tsx` file.
```tsx
// pages/_app.tsx
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
export default function App(props) {
const { Component, pageProps } = props;
return (
-
+
-
+
);
}
```
## Client-side routing
-The `AppProvider` for React Router includes routing out-of-the-box for projects using [react-router-dom](https://www.npmjs.com/package/react-router-dom).
+The `ReactRouterAppProvider` includes routing out-of-the-box for projects using [react-router](https://www.npmjs.com/package/react-router).
-This specific `AppProvider` is recommended when building single-page applications with tools such as [Vite](https://vite.dev/), as you do not have to manually configure your app routing, making the integration automatic and seamless.
+This specific `ReactRouterAppProvider` is recommended when building single-page applications with tools such as [Vite](https://vite.dev/), as you do not have to manually configure your app routing, making the integration automatic and seamless.
```tsx
-import { AppProvider } from '@toolpad/core/react-router-dom';
+import { ReactRouterAppProvider } from '@toolpad/core/react-router';
```
## Theming
diff --git a/docs/data/toolpad/core/integrations/ReactRouter.js b/docs/data/toolpad/core/integrations/ReactRouter.js
index 87b5dea39d9..8498907f251 100644
--- a/docs/data/toolpad/core/integrations/ReactRouter.js
+++ b/docs/data/toolpad/core/integrations/ReactRouter.js
@@ -4,8 +4,8 @@ import { createTheme } from '@mui/material/styles';
import Typography from '@mui/material/Typography';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
-import { createMemoryRouter, RouterProvider, Outlet } from 'react-router-dom';
-import { AppProvider } from '@toolpad/core/react-router-dom';
+import { createMemoryRouter, RouterProvider, Outlet } from 'react-router';
+import { ReactRouterAppProvider } from '@toolpad/core/react-router';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { PageContainer } from '@toolpad/core/PageContainer';
@@ -67,14 +67,14 @@ function App(props) {
const { window } = props;
return (
-
-
+
);
}
diff --git a/docs/data/toolpad/core/integrations/ReactRouter.tsx b/docs/data/toolpad/core/integrations/ReactRouter.tsx
index dc2df442938..e84f94173e4 100644
--- a/docs/data/toolpad/core/integrations/ReactRouter.tsx
+++ b/docs/data/toolpad/core/integrations/ReactRouter.tsx
@@ -3,8 +3,8 @@ import { createTheme } from '@mui/material/styles';
import Typography from '@mui/material/Typography';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
-import { createMemoryRouter, RouterProvider, Outlet } from 'react-router-dom';
-import { AppProvider } from '@toolpad/core/react-router-dom';
+import { createMemoryRouter, RouterProvider, Outlet } from 'react-router';
+import { ReactRouterAppProvider } from '@toolpad/core/react-router';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { PageContainer } from '@toolpad/core/PageContainer';
import type { Navigation } from '@toolpad/core/AppProvider';
@@ -67,14 +67,14 @@ function App(props: { window?: Window }) {
const { window } = props;
return (
-
-
+
);
}
diff --git a/docs/data/toolpad/core/integrations/nextjs-approuter.md b/docs/data/toolpad/core/integrations/nextjs-approuter.md
index 8784c51e707..993f6964071 100644
--- a/docs/data/toolpad/core/integrations/nextjs-approuter.md
+++ b/docs/data/toolpad/core/integrations/nextjs-approuter.md
@@ -26,12 +26,12 @@ yarn add install @mui/material-nextjs @emotion/cache
-## Wrap your application with `AppProvider`
+## Wrap your application with `NextAppProvider`
-In your root layout file (for example, `app/layout.tsx`), wrap your application with the `AppProvider`:
+In your root layout file (for example, `app/layout.tsx`), wrap your application with the `NextAppProvider`:
```tsx title="app/layout.tsx"
-import { AppProvider } from '@toolpad/core/AppProvider';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import LinearProgress from '@mui/material/LinearProgress';
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
@@ -39,16 +39,16 @@ export default function RootLayout({ children }: { children: React.ReactNode })
return (
}>
-
+
{children}
-
+
);
}
```
-You can find details on the `AppProvider` props on the [AppProvider](/toolpad/core/react-app-provider/) page.
+You can find details on the `NextAppProvider` props on the [AppProvider](/toolpad/core/react-app-provider/) page.
:::info
The `AppRouterCacheProvider` component is not required to use Toolpad Core, but it's recommended to use it to ensure that the styles are appended to the `` and not rendering in the ``.
diff --git a/docs/data/toolpad/core/integrations/nextjs-pagesrouter.md b/docs/data/toolpad/core/integrations/nextjs-pagesrouter.md
index c6e8171d805..6eac0cbe05d 100644
--- a/docs/data/toolpad/core/integrations/nextjs-pagesrouter.md
+++ b/docs/data/toolpad/core/integrations/nextjs-pagesrouter.md
@@ -26,13 +26,13 @@ yarn add install @mui/material-nextjs @emotion/cache
-## Wrap your application with `AppProvider`
+## Wrap your application with `NextAppProvider`
-In your root layout file (for example, `pages/_app.tsx`), wrap your application with the `AppProvider`:
+In your root layout file (for example, `pages/_app.tsx`), wrap your application with the `NextAppProvider`:
```tsx title="pages/_app.tsx"
import * as React from 'react';
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import { PageContainer } from '@toolpad/core/PageContainer';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import Head from 'next/head';
@@ -63,13 +63,13 @@ export default function App({ Component }: { Component: React.ElementType }) {
-
+
-
+
);
}
@@ -221,7 +221,7 @@ Modify `_app.tsx` to include the `authentication` prop and other helpers:
```tsx title="pages/_app.tsx"
import * as React from 'react';
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { PageContainer } from '@toolpad/core/PageContainer';
import Head from 'next/head';
@@ -294,14 +294,14 @@ function AppLayout({ children }: { children: React.ReactNode }) {
-
{children}
-
+
);
}
diff --git a/docs/data/toolpad/core/integrations/react-router.md b/docs/data/toolpad/core/integrations/react-router.md
index e0fd48b0d82..0ba513f938e 100644
--- a/docs/data/toolpad/core/integrations/react-router.md
+++ b/docs/data/toolpad/core/integrations/react-router.md
@@ -1,21 +1,21 @@
---
-title: React router - Integration
+title: React Router - Integration
---
# React Router
To integrate Toolpad Core into a single-page app (with Vite, for example) using React Router, follow these steps.
-## Wrap all your pages in an `AppProvider`
+## Wrap all your pages in a `ReactRouterAppProvider`
-In your router configuration (e.g.: `src/main.tsx`), use a shared component or element (e.g.: `src/App.tsx`) as a root **layout route** that wraps the whole application with the `AppProvider` from `@toolpad/core/react-router-dom`.
+In your router configuration (for example `src/main.tsx`), use a shared component or element (for example `src/App.tsx`) as a root **layout route** that wraps the whole application with the `ReactRouterAppProvider` from `@toolpad/core/react-router`.
-You must use the `` component from `react-router-dom` in this root layout element or component.
+You must use the `` component from `react-router` in this root layout element or component.
```tsx title="src/main.tsx"
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
-import { createBrowserRouter, RouterProvider } from 'react-router-dom';
+import { createBrowserRouter, RouterProvider } from 'react-router';
import App from './App';
import DashboardPage from './pages';
import OrdersPage from './pages/orders';
@@ -37,8 +37,8 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
import * as React from 'react';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
-import { AppProvider } from '@toolpad/core/react-router-dom';
-import { Outlet } from 'react-router-dom';
+import { ReactRouterAppProvider } from '@toolpad/core/react-router';
+import { Outlet } from 'react-router';
import type { Navigation } from '@toolpad/core';
const NAVIGATION: Navigation = [
@@ -63,20 +63,20 @@ const BRANDING = {
export default function App() {
return (
-
+
-
+
);
}
```
## Create a dashboard layout
-Create a layout file for your dashboard pages (e.g.: `src/layouts/dashboard.tsx`), to also be used as a layout route with the `` component from `react-router-dom`:
+Create a layout file for your dashboard pages (for example `src/layouts/dashboard.tsx`), to also be used as a layout route with the `` component from `react-router`:
```tsx title="src/layouts/dashboard.tsx"
import * as React from 'react';
-import { Outlet } from 'react-router-dom';
+import { Outlet } from 'react-router';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { PageContainer } from '@toolpad/core/PageContainer';
@@ -93,7 +93,7 @@ export default function Layout() {
The [`DashboardLayout`](/toolpad/core/react-dashboard-layout/) component provides a consistent layout for your dashboard pages, including a sidebar, navigation, and header. The [`PageContainer`](/toolpad/core/react-page-container/) component is used to wrap the page content, and provides breadcrumbs for navigation.
-You can then add this layout component to your React Router configuration (e.g.: `src/main.tsx`), as a child of the root layout route created above.
+You can then add this layout component to your React Router configuration (for example `src/main.tsx`), as a child of the root layout route created above.
```tsx title="src/main.tsx"
import Layout from './layouts/dashboard';
@@ -115,7 +115,7 @@ const router = createBrowserRouter([
## Create pages
-Create a dashboard page (e.g.: `src/pages/index.tsx`) and an orders page (`src/pages/orders.tsx`).
+Create a dashboard page (for example `src/pages/index.tsx`) and an orders page (`src/pages/orders.tsx`).
```tsx title="src/pages/index.tsx"
import * as React from 'react';
@@ -135,7 +135,7 @@ export default function OrdersPage() {
}
```
-You can then add these page components as routes to your React Router configuration (e.g.: `src/main.tsx`). By adding them as children of the layout route created above, they are automatically wrapped with that dashboard layout:
+You can then add these page components as routes to your React Router configuration (for example `src/main.tsx`). By adding them as children of the layout route created above, they are automatically wrapped with that dashboard layout:
```tsx title="src/main.tsx"
import DashboardPage from './pages';
@@ -205,8 +205,8 @@ export function useSession() {
import * as React from 'react';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
-import { AppProvider } from '@toolpad/core/react-router-dom';
-import { Outlet, useNavigate } from 'react-router-dom';
+import { ReactRouterAppProvider } from '@toolpad/core/react-router';
+import { Outlet, useNavigate } from 'react-router';
import type { Navigation, Session } from '@toolpad/core';
import { SessionContext } from './SessionContext';
@@ -250,14 +250,14 @@ export default function App() {
return (
-
-
+
);
}
@@ -267,7 +267,7 @@ export default function App() {
```tsx title="src/layouts/dashboard.tsx"
import * as React from 'react';
-import { Outlet, Navigate, useLocation } from 'react-router-dom';
+import { Outlet, Navigate, useLocation } from 'react-router';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { PageContainer } from '@toolpad/core/PageContainer';
import { useSession } from '../SessionContext';
@@ -302,7 +302,7 @@ You can protect any page or groups of pages through this mechanism.
import * as React from 'react';
import { SignInPage } from '@toolpad/core/SignInPage';
import type { Session } from '@toolpad/core/AppProvider';
-import { useNavigate } from 'react-router-dom';
+import { useNavigate } from 'react-router';
import { useSession } from '../SessionContext';
const fakeAsyncGetSession = async (formData: any): Promise => {
@@ -354,7 +354,7 @@ export default function SignIn() {
```tsx title="src/main.tsx"
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
-import { createBrowserRouter, RouterProvider } from 'react-router-dom';
+import { createBrowserRouter, RouterProvider } from 'react-router';
import App from './App';
import Layout from './layouts/dashboard';
import DashboardPage from './pages';
diff --git a/docs/data/toolpad/core/introduction/base-concepts.md b/docs/data/toolpad/core/introduction/base-concepts.md
index be319e433ee..ae008ad48dc 100644
--- a/docs/data/toolpad/core/introduction/base-concepts.md
+++ b/docs/data/toolpad/core/introduction/base-concepts.md
@@ -67,9 +67,9 @@ You can pass the router implementation to the `AppProvider` component using the
:::
:::success
-If you are using Next.js, use the `AppProvider` exported from `@toolpad/core/nextjs`.
+If you are using Next.js, use the `NextAppProvider` exported from `@toolpad/core/nextjs`.
-If you are building a single-page application (with [Vite](https://vite.dev/), for example) using React Router for routing, use the `AppProvider` exported from `@toolpad/core/react-router-dom`.
+If you are building a single-page application (with [Vite](https://vite.dev/), for example) using React Router for routing, use the `ReactRouterAppProvider` exported from `@toolpad/core/react-router`.
This automatically sets up the router for you, so that you don't need to pass the `router` prop.
:::
diff --git a/docs/package.json b/docs/package.json
index 4bba7ccf7ae..afffad15a6b 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -77,7 +77,7 @@
"react-dom": "18.3.1",
"react-hook-form": "7.53.2",
"react-is": "18.3.1",
- "react-router": "6.26.2",
+ "react-router": "7.1.0",
"react-router-dom": "6.26.2",
"react-runner": "1.0.5",
"react-simple-code-editor": "0.14.1",
diff --git a/docs/pages/toolpad/core/api/app-provider.json b/docs/pages/toolpad/core/api/app-provider.json
index bb6ac8cd868..6918852f106 100644
--- a/docs/pages/toolpad/core/api/app-provider.json
+++ b/docs/pages/toolpad/core/api/app-provider.json
@@ -39,7 +39,7 @@
"name": "AppProvider",
"imports": [
"import { AppProvider } from '@toolpad/core/AppProvider';",
- "import { AppProvider } from '@toolpad/core';\nimport { AppProvider } from '@toolpad/core/nextjs'; // Next.js\nimport { AppProvider } from '@toolpad/core/react-router-dom'; // React Router"
+ "import { AppProvider } from '@toolpad/core';\nimport { NextAppProvider } from '@toolpad/core/nextjs'; // Next.js\nimport { ReactRouterAppProvider } from '@toolpad/core/react-router'; // React Router"
],
"classes": [],
"spread": true,
diff --git a/examples/core/auth-nextjs-email/src/app/layout.tsx b/examples/core/auth-nextjs-email/src/app/layout.tsx
index aee998fac8f..cfc6d97e016 100644
--- a/examples/core/auth-nextjs-email/src/app/layout.tsx
+++ b/examples/core/auth-nextjs-email/src/app/layout.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
@@ -41,14 +41,14 @@ export default async function RootLayout(props: { children: React.ReactNode }) {
-
{props.children}
-
+
diff --git a/examples/core/auth-nextjs-pages-nextauth-4/src/pages/_app.tsx b/examples/core/auth-nextjs-pages-nextauth-4/src/pages/_app.tsx
index b8e40df7033..c5247a06bd5 100644
--- a/examples/core/auth-nextjs-pages-nextauth-4/src/pages/_app.tsx
+++ b/examples/core/auth-nextjs-pages-nextauth-4/src/pages/_app.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import Head from 'next/head';
import { useRouter } from 'next/router';
@@ -72,14 +72,14 @@ function AppLayout({ children }: { children: React.ReactNode }) {
-
{children}
-
+
);
}
diff --git a/examples/core/auth-nextjs-pages/src/pages/_app.tsx b/examples/core/auth-nextjs-pages/src/pages/_app.tsx
index e2642586973..0a1f564cb66 100644
--- a/examples/core/auth-nextjs-pages/src/pages/_app.tsx
+++ b/examples/core/auth-nextjs-pages/src/pages/_app.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { PageContainer } from '@toolpad/core/PageContainer';
import Head from 'next/head';
@@ -71,14 +71,14 @@ function AppLayout({ children }: { children: React.ReactNode }) {
-
{children}
-
+
);
}
diff --git a/examples/core/auth-nextjs-passkey/src/app/layout.tsx b/examples/core/auth-nextjs-passkey/src/app/layout.tsx
index 016a1662c3c..b91589627b4 100644
--- a/examples/core/auth-nextjs-passkey/src/app/layout.tsx
+++ b/examples/core/auth-nextjs-passkey/src/app/layout.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
@@ -40,14 +40,14 @@ export default async function RootLayout(props: { children: React.ReactNode }) {
-
{props.children}
-
+
diff --git a/examples/core/auth-nextjs-themed/app/layout.tsx b/examples/core/auth-nextjs-themed/app/layout.tsx
index fbf6fb8f44d..3fceadb73cb 100644
--- a/examples/core/auth-nextjs-themed/app/layout.tsx
+++ b/examples/core/auth-nextjs-themed/app/layout.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
@@ -36,14 +36,14 @@ export default async function RootLayout({ children }: Readonly<{ children: Reac
-
{children}
-
+
diff --git a/examples/core/auth-nextjs/src/app/layout.tsx b/examples/core/auth-nextjs/src/app/layout.tsx
index 6ec47c8dfc5..ed6df4dbcc3 100644
--- a/examples/core/auth-nextjs/src/app/layout.tsx
+++ b/examples/core/auth-nextjs/src/app/layout.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
@@ -40,14 +40,14 @@ export default async function RootLayout(props: { children: React.ReactNode }) {
-
{props.children}
-
+
diff --git a/examples/core/auth-vite/package.json b/examples/core/auth-vite/package.json
index cb0751eb5c6..d1d1bc8abd1 100644
--- a/examples/core/auth-vite/package.json
+++ b/examples/core/auth-vite/package.json
@@ -15,7 +15,7 @@
"@toolpad/core": "latest",
"react": "^18",
"react-dom": "^18",
- "react-router-dom": "^6"
+ "react-router": "^7"
},
"devDependencies": {
"@types/react": "^18",
diff --git a/examples/core/auth-vite/src/App.tsx b/examples/core/auth-vite/src/App.tsx
index 075aa3c62c1..1a54541e4ff 100644
--- a/examples/core/auth-vite/src/App.tsx
+++ b/examples/core/auth-vite/src/App.tsx
@@ -1,9 +1,9 @@
import * as React from 'react';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
-import { AppProvider } from '@toolpad/core/react-router-dom';
-import { Outlet, useNavigate } from 'react-router-dom';
-import type { Navigation, Session } from '@toolpad/core';
+import { ReactRouterAppProvider } from '@toolpad/core/react-router';
+import { Outlet, useNavigate } from 'react-router';
+import type { Navigation, Session } from '@toolpad/core/AppProvider';
import { SessionContext } from './SessionContext';
const NAVIGATION: Navigation = [
@@ -43,14 +43,14 @@ export default function App() {
return (
-
-
+
);
}
diff --git a/examples/core/auth-vite/src/layouts/dashboard.tsx b/examples/core/auth-vite/src/layouts/dashboard.tsx
index 39b681178b6..03a99900aa0 100644
--- a/examples/core/auth-vite/src/layouts/dashboard.tsx
+++ b/examples/core/auth-vite/src/layouts/dashboard.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { Outlet, Navigate, useLocation } from 'react-router-dom';
+import { Outlet, Navigate, useLocation } from 'react-router';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { PageContainer } from '@toolpad/core/PageContainer';
import { useSession } from '../SessionContext';
diff --git a/examples/core/auth-vite/src/main.tsx b/examples/core/auth-vite/src/main.tsx
index ceee289fe2c..d5929bec598 100644
--- a/examples/core/auth-vite/src/main.tsx
+++ b/examples/core/auth-vite/src/main.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
-import { createBrowserRouter, RouterProvider } from 'react-router-dom';
+import { createBrowserRouter, RouterProvider } from 'react-router';
import App from './App';
import Layout from './layouts/dashboard';
import DashboardPage from './pages';
diff --git a/examples/core/auth-vite/src/pages/signIn.tsx b/examples/core/auth-vite/src/pages/signIn.tsx
index f01c9e9993a..17008f42546 100644
--- a/examples/core/auth-vite/src/pages/signIn.tsx
+++ b/examples/core/auth-vite/src/pages/signIn.tsx
@@ -2,7 +2,7 @@
import * as React from 'react';
import { SignInPage } from '@toolpad/core/SignInPage';
import type { Session } from '@toolpad/core/AppProvider';
-import { useNavigate } from 'react-router-dom';
+import { useNavigate } from 'react-router';
import { useSession } from '../SessionContext';
const fakeAsyncGetSession = async (formData: any): Promise => {
diff --git a/examples/core/firebase-vite/package.json b/examples/core/firebase-vite/package.json
index 029bb677f2b..196dfc54160 100644
--- a/examples/core/firebase-vite/package.json
+++ b/examples/core/firebase-vite/package.json
@@ -23,7 +23,7 @@
"@toolpad/core": "latest",
"react": "^18",
"react-dom": "^18",
- "react-router-dom": "^6"
+ "react-router": "^7"
},
"devDependencies": {
"@types/react": "^18",
diff --git a/examples/core/firebase-vite/src/App.tsx b/examples/core/firebase-vite/src/App.tsx
index 617a1d0b0c6..c3a9b09aec3 100644
--- a/examples/core/firebase-vite/src/App.tsx
+++ b/examples/core/firebase-vite/src/App.tsx
@@ -1,9 +1,9 @@
import * as React from 'react';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
-import { Outlet } from 'react-router-dom';
+import { Outlet } from 'react-router';
import type { User } from 'firebase/auth';
-import { AppProvider } from '@toolpad/core/react-router-dom';
+import { ReactRouterAppProvider } from '@toolpad/core/react-router';
import type { Navigation, Authentication } from '@toolpad/core/AppProvider';
import { firebaseSignOut, signInWithGoogle, onAuthStateChanged } from './firebase/auth';
import SessionContext, { type Session } from './SessionContext';
@@ -67,7 +67,7 @@ export default function App() {
}, []);
return (
-
-
+
);
}
diff --git a/examples/core/firebase-vite/src/layouts/dashboard.tsx b/examples/core/firebase-vite/src/layouts/dashboard.tsx
index 96c8db7ca97..07e4183641b 100644
--- a/examples/core/firebase-vite/src/layouts/dashboard.tsx
+++ b/examples/core/firebase-vite/src/layouts/dashboard.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import LinearProgress from '@mui/material/LinearProgress';
-import { Outlet, Navigate, useLocation } from 'react-router-dom';
+import { Outlet, Navigate, useLocation } from 'react-router';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { PageContainer } from '@toolpad/core/PageContainer';
import { Account } from '@toolpad/core/Account';
diff --git a/examples/core/firebase-vite/src/main.tsx b/examples/core/firebase-vite/src/main.tsx
index 1ccc9f6b4f5..a806e8e3b68 100644
--- a/examples/core/firebase-vite/src/main.tsx
+++ b/examples/core/firebase-vite/src/main.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
-import { createBrowserRouter, RouterProvider } from 'react-router-dom';
+import { createBrowserRouter, RouterProvider } from 'react-router';
import App from './App';
import Layout from './layouts/dashboard';
import DashboardPage from './pages';
diff --git a/examples/core/firebase-vite/src/pages/signin.tsx b/examples/core/firebase-vite/src/pages/signin.tsx
index 47f34565c7a..32e8bdc8e34 100644
--- a/examples/core/firebase-vite/src/pages/signin.tsx
+++ b/examples/core/firebase-vite/src/pages/signin.tsx
@@ -3,7 +3,7 @@ import * as React from 'react';
import Alert from '@mui/material/Alert';
import LinearProgress from '@mui/material/LinearProgress';
import { SignInPage } from '@toolpad/core/SignInPage';
-import { Navigate, useNavigate } from 'react-router-dom';
+import { Navigate, useNavigate } from 'react-router';
import { useSession, type Session } from '../SessionContext';
import { signInWithGoogle, signInWithGithub, signInWithCredentials } from '../firebase/auth';
diff --git a/examples/core/tutorial/app/layout.tsx b/examples/core/tutorial/app/layout.tsx
index 06dd5f497d2..490c41047c0 100644
--- a/examples/core/tutorial/app/layout.tsx
+++ b/examples/core/tutorial/app/layout.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
@@ -30,9 +30,9 @@ export default function RootLayout({ children }: Readonly<{ children: React.Reac
}>
-
+
{children}
-
+
diff --git a/examples/core/vite/package.json b/examples/core/vite/package.json
index afe44cc4cf7..3008c9ec588 100644
--- a/examples/core/vite/package.json
+++ b/examples/core/vite/package.json
@@ -15,7 +15,7 @@
"@toolpad/core": "latest",
"react": "^18",
"react-dom": "^18",
- "react-router-dom": "^6"
+ "react-router": "^7"
},
"devDependencies": {
"@types/react": "^18",
diff --git a/examples/core/vite/src/App.tsx b/examples/core/vite/src/App.tsx
index 2c6147c8788..ea7cb04796c 100644
--- a/examples/core/vite/src/App.tsx
+++ b/examples/core/vite/src/App.tsx
@@ -1,8 +1,9 @@
import * as React from 'react';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
-import { Outlet } from 'react-router-dom';
-import { AppProvider, type Navigation } from '@toolpad/core/react-router-dom';
+import { Outlet } from 'react-router';
+import { ReactRouterAppProvider } from '@toolpad/core/react-router';
+import type { Navigation } from '@toolpad/core/AppProvider';
const NAVIGATION: Navigation = [
{
@@ -26,8 +27,8 @@ const BRANDING = {
export default function App() {
return (
-
+
-
+
);
}
diff --git a/examples/core/vite/src/layouts/dashboard.tsx b/examples/core/vite/src/layouts/dashboard.tsx
index c540feb6e0f..84b8584f7c6 100644
--- a/examples/core/vite/src/layouts/dashboard.tsx
+++ b/examples/core/vite/src/layouts/dashboard.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { Outlet } from 'react-router-dom';
+import { Outlet } from 'react-router';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { PageContainer } from '@toolpad/core/PageContainer';
diff --git a/examples/core/vite/src/main.tsx b/examples/core/vite/src/main.tsx
index 882c91c0bff..cee7678c361 100644
--- a/examples/core/vite/src/main.tsx
+++ b/examples/core/vite/src/main.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
-import { createBrowserRouter, RouterProvider } from 'react-router-dom';
+import { createBrowserRouter, RouterProvider } from 'react-router';
import App from './App';
import Layout from './layouts/dashboard';
import DashboardPage from './pages';
diff --git a/packages/create-toolpad-app/src/templates/nextjs-app/rootLayout.ts b/packages/create-toolpad-app/src/templates/nextjs-app/rootLayout.ts
index 2ada7023096..b0c9aed2ad5 100644
--- a/packages/create-toolpad-app/src/templates/nextjs-app/rootLayout.ts
+++ b/packages/create-toolpad-app/src/templates/nextjs-app/rootLayout.ts
@@ -4,7 +4,7 @@ const rootLayout: Template = (options) => {
const authEnabled = options.auth;
return `import * as React from 'react';
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
@@ -59,7 +59,7 @@ export default ${authEnabled ? 'async ' : ''}function RootLayout(props: { childr
${authEnabled ? '' : ''}
${authEnabled ? '' : '}>'}
-
{props.children}
-
+
${authEnabled ? '' : ''}
${authEnabled ? '' : ''}
diff --git a/packages/create-toolpad-app/src/templates/nextjs-pages/app.ts b/packages/create-toolpad-app/src/templates/nextjs-pages/app.ts
index 4f4f24b9092..8689e8b9b6b 100644
--- a/packages/create-toolpad-app/src/templates/nextjs-pages/app.ts
+++ b/packages/create-toolpad-app/src/templates/nextjs-pages/app.ts
@@ -4,7 +4,7 @@ const app: Template = (options) => {
const authEnabled = options.auth;
return `import * as React from 'react';
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { PageContainer } from '@toolpad/core/PageContainer';
import Head from 'next/head';
@@ -104,7 +104,7 @@ function AppLayout({ children }: { children: React.ReactNode }) {
-
{children}
-
+
);
}
diff --git a/packages/toolpad-core/package.json b/packages/toolpad-core/package.json
index 0ac7906f86c..cb1d58451f0 100644
--- a/packages/toolpad-core/package.json
+++ b/packages/toolpad-core/package.json
@@ -76,7 +76,7 @@
"next": "^15.1.2",
"next-router-mock": "^0.9.13",
"playwright": "^1.47.2",
- "react-router-dom": "6.26.2",
+ "react-router": "7.1.0",
"sinon": "^19.0.2",
"vitest": "2.1.8"
},
@@ -85,13 +85,13 @@
"@mui/material": "5 - 6",
"next": "^14 || ^15",
"react": "^18",
- "react-router-dom": "^6"
+ "react-router": "^7"
},
"peerDependenciesMeta": {
"next": {
"optional": true
},
- "react-router-dom": {
+ "react-router": {
"optional": true
}
},
diff --git a/packages/toolpad-core/src/nextjs/AppProvider.tsx b/packages/toolpad-core/src/nextjs/AppProvider.tsx
deleted file mode 100644
index 6555738697b..00000000000
--- a/packages/toolpad-core/src/nextjs/AppProvider.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-'use client';
-import * as React from 'react';
-import { useRouter } from 'next/compat/router';
-import { AppProviderNextApp } from './AppProviderNextApp';
-import { AppProviderNextPages } from './AppProviderNextPages';
-import type { AppProviderProps } from '../AppProvider';
-
-/**
- * @ignore - internal component.
- */
-function AppProvider(props: AppProviderProps) {
- const router = useRouter();
- const AppProviderComponent = router ? AppProviderNextPages : AppProviderNextApp;
- return ;
-}
-
-export { AppProvider };
diff --git a/packages/toolpad-core/src/nextjs/AppProvider.test.tsx b/packages/toolpad-core/src/nextjs/NextAppProvider.test.tsx
similarity index 90%
rename from packages/toolpad-core/src/nextjs/AppProvider.test.tsx
rename to packages/toolpad-core/src/nextjs/NextAppProvider.test.tsx
index c171a039395..ba23bedc3d0 100644
--- a/packages/toolpad-core/src/nextjs/AppProvider.test.tsx
+++ b/packages/toolpad-core/src/nextjs/NextAppProvider.test.tsx
@@ -5,7 +5,7 @@
import * as React from 'react';
import { describe, test, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
-import { AppProvider } from './AppProvider';
+import { NextAppProvider } from './NextAppProvider';
import { Router } from '../AppProvider';
vi.mock('next/navigation', () => {
@@ -39,7 +39,7 @@ function RouterTest({ children }: RouterTestProps) {
};
}, [pathname]);
- return {children};
+ return {children};
}
describe('Nextjs AppProvider', () => {
diff --git a/packages/toolpad-core/src/nextjs/NextAppProvider.tsx b/packages/toolpad-core/src/nextjs/NextAppProvider.tsx
new file mode 100644
index 00000000000..ccfdbfead70
--- /dev/null
+++ b/packages/toolpad-core/src/nextjs/NextAppProvider.tsx
@@ -0,0 +1,19 @@
+'use client';
+import * as React from 'react';
+import { useRouter } from 'next/compat/router';
+import { NextAppProviderApp } from './NextAppProviderApp';
+import { NextAppProviderPages } from './NextAppProviderPages';
+import type { AppProviderProps } from '../AppProvider';
+
+function NextAppProvider(props: AppProviderProps) {
+ const router = useRouter();
+ const AppProvider = router ? NextAppProviderPages : NextAppProviderApp;
+ return ;
+}
+
+export {
+ NextAppProvider,
+ /** TODO: Old usage, remove export from v0.14.0 */
+ /** @deprecated Import `NextAppProvider` instead. */
+ NextAppProvider as AppProvider,
+};
diff --git a/packages/toolpad-core/src/nextjs/AppProviderNextApp.tsx b/packages/toolpad-core/src/nextjs/NextAppProviderApp.tsx
similarity index 93%
rename from packages/toolpad-core/src/nextjs/AppProviderNextApp.tsx
rename to packages/toolpad-core/src/nextjs/NextAppProviderApp.tsx
index 64b59b936e9..f01b51a653d 100644
--- a/packages/toolpad-core/src/nextjs/AppProviderNextApp.tsx
+++ b/packages/toolpad-core/src/nextjs/NextAppProviderApp.tsx
@@ -6,7 +6,7 @@ import type { AppProviderProps, Navigate, Router } from '../AppProvider';
/**
* @ignore - internal component.
*/
-export function AppProviderNextApp(props: AppProviderProps) {
+export function NextAppProviderApp(props: AppProviderProps) {
const pathname = usePathname();
const searchParams = useSearchParams();
const { push, replace } = useRouter();
diff --git a/packages/toolpad-core/src/nextjs/AppProviderNextPages.tsx b/packages/toolpad-core/src/nextjs/NextAppProviderPages.tsx
similarity index 95%
rename from packages/toolpad-core/src/nextjs/AppProviderNextPages.tsx
rename to packages/toolpad-core/src/nextjs/NextAppProviderPages.tsx
index 14763fbd2f7..c26f6c9fc0d 100644
--- a/packages/toolpad-core/src/nextjs/AppProviderNextPages.tsx
+++ b/packages/toolpad-core/src/nextjs/NextAppProviderPages.tsx
@@ -7,7 +7,7 @@ import type { AppProviderProps, Navigate, Router } from '../AppProvider';
/**
* @ignore - internal component.
*/
-export function AppProviderNextPages(props: AppProviderProps) {
+export function NextAppProviderPages(props: AppProviderProps) {
const { push, replace, asPath, query } = useRouter();
const search = React.useMemo(() => {
diff --git a/packages/toolpad-core/src/nextjs/index.tsx b/packages/toolpad-core/src/nextjs/index.tsx
index bd2c0cdccb2..c1b8b9cdcbf 100644
--- a/packages/toolpad-core/src/nextjs/index.tsx
+++ b/packages/toolpad-core/src/nextjs/index.tsx
@@ -1 +1 @@
-export * from './AppProvider';
+export * from './NextAppProvider';
diff --git a/packages/toolpad-core/src/react-router-dom/index.tsx b/packages/toolpad-core/src/react-router-dom/index.tsx
deleted file mode 100644
index bd2c0cdccb2..00000000000
--- a/packages/toolpad-core/src/react-router-dom/index.tsx
+++ /dev/null
@@ -1 +0,0 @@
-export * from './AppProvider';
diff --git a/packages/toolpad-core/src/react-router-dom/AppProvider.test.tsx b/packages/toolpad-core/src/react-router/ReactRouterAppProvider.test.tsx
similarity index 70%
rename from packages/toolpad-core/src/react-router-dom/AppProvider.test.tsx
rename to packages/toolpad-core/src/react-router/ReactRouterAppProvider.test.tsx
index bde0bfc7743..a63e5959264 100644
--- a/packages/toolpad-core/src/react-router-dom/AppProvider.test.tsx
+++ b/packages/toolpad-core/src/react-router/ReactRouterAppProvider.test.tsx
@@ -5,15 +5,15 @@
import * as React from 'react';
import { describe, test, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
-import { BrowserRouter } from 'react-router-dom';
-import { AppProvider } from './AppProvider';
+import { BrowserRouter } from 'react-router';
+import { ReactRouterAppProvider } from './ReactRouterAppProvider';
describe('React Router AppProvider', () => {
test('renders content correctly', async () => {
// placeholder test
render(
- Hello
+ Hello
,
);
diff --git a/packages/toolpad-core/src/react-router-dom/AppProvider.tsx b/packages/toolpad-core/src/react-router/ReactRouterAppProvider.tsx
similarity index 65%
rename from packages/toolpad-core/src/react-router-dom/AppProvider.tsx
rename to packages/toolpad-core/src/react-router/ReactRouterAppProvider.tsx
index 8977c032337..afb1fdaf89a 100644
--- a/packages/toolpad-core/src/react-router-dom/AppProvider.tsx
+++ b/packages/toolpad-core/src/react-router/ReactRouterAppProvider.tsx
@@ -1,17 +1,9 @@
'use client';
import * as React from 'react';
-import { useSearchParams, useLocation, useNavigate } from 'react-router-dom';
-import {
- AppProvider as AppProviderComponent,
- type AppProviderProps,
- Navigate,
- Router,
-} from '../AppProvider';
+import { useSearchParams, useLocation, useNavigate } from 'react-router';
+import { AppProvider, type AppProviderProps, Navigate, Router } from '../AppProvider/AppProvider';
-/**
- * @ignore - internal component.
- */
-function AppProvider(props: AppProviderProps) {
+function ReactRouterAppProvider(props: AppProviderProps) {
const { pathname } = useLocation();
const [searchParams] = useSearchParams();
const navigate = useNavigate();
@@ -38,7 +30,12 @@ function AppProvider(props: AppProviderProps) {
[pathname, searchParams, navigateImpl],
);
- return ;
+ return ;
}
-export { AppProvider };
+export {
+ ReactRouterAppProvider,
+ /** TODO: Old usage, remove export from v0.14.0 */
+ /** @deprecated Import `ReactRouterAppProvider` instead. */
+ ReactRouterAppProvider as AppProvider,
+};
diff --git a/packages/toolpad-core/src/react-router/index.tsx b/packages/toolpad-core/src/react-router/index.tsx
new file mode 100644
index 00000000000..24a972e324c
--- /dev/null
+++ b/packages/toolpad-core/src/react-router/index.tsx
@@ -0,0 +1 @@
+export * from './ReactRouterAppProvider';
diff --git a/packages/toolpad-studio/package.json b/packages/toolpad-studio/package.json
index aa3f5ddd217..584b0b27919 100644
--- a/packages/toolpad-studio/package.json
+++ b/packages/toolpad-studio/package.json
@@ -134,7 +134,7 @@
"react-inspector": "6.0.2",
"react-is": "18.3.1",
"react-resizable-panels": "2.1.7",
- "react-router-dom": "6.26.2",
+ "react-router": "7.1.0",
"semver": "7.6.3",
"serialize-javascript": "6.0.2",
"superjson": "2.0.0",
diff --git a/packages/toolpad-studio/src/runtime/AppLayout.tsx b/packages/toolpad-studio/src/runtime/AppLayout.tsx
index 7c25b46db1b..259375923f3 100644
--- a/packages/toolpad-studio/src/runtime/AppLayout.tsx
+++ b/packages/toolpad-studio/src/runtime/AppLayout.tsx
@@ -1,8 +1,8 @@
import * as React from 'react';
import { Box, useTheme } from '@mui/material';
-import { useNavigate, useSearchParams } from 'react-router-dom';
+import { useNavigate, useSearchParams } from 'react-router';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
-import { AppProvider } from '@toolpad/core/react-router-dom';
+import { ReactRouterAppProvider } from '@toolpad/core/react-router';
import { AuthContext } from './useAuth';
const TOOLPAD_DISPLAY_MODE_URL_PARAM = 'toolpad-display';
@@ -83,7 +83,7 @@ export function AppLayout({
);
return (
-
+
);
}
diff --git a/packages/toolpad-studio/src/runtime/PreviewHeader.tsx b/packages/toolpad-studio/src/runtime/PreviewHeader.tsx
index e411ab74638..4525e741b18 100644
--- a/packages/toolpad-studio/src/runtime/PreviewHeader.tsx
+++ b/packages/toolpad-studio/src/runtime/PreviewHeader.tsx
@@ -1,7 +1,7 @@
import * as React from 'react';
import { Button, Typography, Box, useTheme, Alert, ButtonProps } from '@mui/material';
import EditIcon from '@mui/icons-material/Edit';
-import { Link, useMatch } from 'react-router-dom';
+import { Link, useMatch } from 'react-router';
import { useAppHost } from '@toolpad/studio-runtime';
function OpenInEditorButton({
diff --git a/packages/toolpad-studio/src/runtime/SignInPage.tsx b/packages/toolpad-studio/src/runtime/SignInPage.tsx
index 501eca11604..23abeb6d71f 100644
--- a/packages/toolpad-studio/src/runtime/SignInPage.tsx
+++ b/packages/toolpad-studio/src/runtime/SignInPage.tsx
@@ -13,7 +13,7 @@ import GitHubIcon from '@mui/icons-material/GitHub';
import PasswordIcon from '@mui/icons-material/Password';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import { LoadingButton } from '@mui/lab';
-import { useSearchParams } from 'react-router-dom';
+import { useSearchParams } from 'react-router';
import { useForm, Controller, SubmitHandler } from 'react-hook-form';
import { AuthProvider, AuthContext } from './useAuth';
import productIconDark from '../../public/product-icon-dark.svg';
diff --git a/packages/toolpad-studio/src/runtime/ToolpadApp.tsx b/packages/toolpad-studio/src/runtime/ToolpadApp.tsx
index 7f095315a08..c47c37b1269 100644
--- a/packages/toolpad-studio/src/runtime/ToolpadApp.tsx
+++ b/packages/toolpad-studio/src/runtime/ToolpadApp.tsx
@@ -58,7 +58,7 @@ import {
useParams,
Outlet,
BrowserRouter,
-} from 'react-router-dom';
+} from 'react-router';
import { ErrorBoundary, FallbackProps } from 'react-error-boundary';
import ErrorIcon from '@mui/icons-material/Error';
import { getBrowserRuntime } from '@toolpad/studio-runtime/jsBrowserRuntime';
diff --git a/packages/toolpad-studio/src/runtime/useAuth.ts b/packages/toolpad-studio/src/runtime/useAuth.ts
index 2800acea214..468e426d1db 100644
--- a/packages/toolpad-studio/src/runtime/useAuth.ts
+++ b/packages/toolpad-studio/src/runtime/useAuth.ts
@@ -1,6 +1,6 @@
import * as React from 'react';
import * as appDom from '@toolpad/studio-runtime/appDom';
-import { useLocation, useNavigate } from 'react-router-dom';
+import { useLocation, useNavigate } from 'react-router';
import { useAppHost } from '@toolpad/studio-runtime';
const AUTH_API_PATH = '/api/auth';
diff --git a/packages/toolpad-studio/src/toolpad/AppEditor/index.tsx b/packages/toolpad-studio/src/toolpad/AppEditor/index.tsx
index b208290d3e4..da33e1199d7 100644
--- a/packages/toolpad-studio/src/toolpad/AppEditor/index.tsx
+++ b/packages/toolpad-studio/src/toolpad/AppEditor/index.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import { styled } from '@mui/material';
-import { useNavigate, useLocation } from 'react-router-dom';
+import { useNavigate, useLocation } from 'react-router';
import PageEditor from './PageEditor';
import { useAppState } from '../AppState';
import AppEditorShell from './AppEditorShell';
diff --git a/packages/toolpad-studio/src/toolpad/AppState.tsx b/packages/toolpad-studio/src/toolpad/AppState.tsx
index bc849b0cb8c..82ee78b5508 100644
--- a/packages/toolpad-studio/src/toolpad/AppState.tsx
+++ b/packages/toolpad-studio/src/toolpad/AppState.tsx
@@ -3,7 +3,7 @@ import { NodeHashes, NodeId } from '@toolpad/studio-runtime';
import { createProvidedContext } from '@toolpad/utils/react';
import invariant from 'invariant';
import { debounce, DebouncedFunc } from 'lodash-es';
-import { useLocation } from 'react-router-dom';
+import { useLocation } from 'react-router';
import { mapValues } from '@toolpad/utils/collections';
import useDebouncedHandler from '@toolpad/utils/hooks/useDebouncedHandler';
import useEventCallback from '@mui/utils/useEventCallback';
diff --git a/packages/toolpad-studio/src/toolpad/Toolpad.tsx b/packages/toolpad-studio/src/toolpad/Toolpad.tsx
index 92a14a7c510..4c2b21f4def 100644
--- a/packages/toolpad-studio/src/toolpad/Toolpad.tsx
+++ b/packages/toolpad-studio/src/toolpad/Toolpad.tsx
@@ -1,7 +1,7 @@
import { CircularProgress, Box, styled, CssBaseline, Button, Stack, Tooltip } from '@mui/material';
import * as React from 'react';
import { ErrorBoundary, FallbackProps } from 'react-error-boundary';
-import { BrowserRouter, Routes, Route, useLocation } from 'react-router-dom';
+import { BrowserRouter, Routes, Route, useLocation } from 'react-router';
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import CloudDoneIcon from '@mui/icons-material/CloudDone';
import SyncIcon from '@mui/icons-material/Sync';
diff --git a/packages/toolpad-studio/src/toolpad/ToolpadShell/ToolpadNavigation.tsx b/packages/toolpad-studio/src/toolpad/ToolpadShell/ToolpadNavigation.tsx
index 9785f3729c6..a8988916c17 100644
--- a/packages/toolpad-studio/src/toolpad/ToolpadShell/ToolpadNavigation.tsx
+++ b/packages/toolpad-studio/src/toolpad/ToolpadShell/ToolpadNavigation.tsx
@@ -11,7 +11,7 @@ import {
IconButton,
Tooltip,
} from '@mui/material';
-import { Link, matchPath, useLocation } from 'react-router-dom';
+import { Link, matchPath, useLocation } from 'react-router';
const DRAWER_WIDTH = 44; // px
diff --git a/packages/toolpad-studio/src/utils/domView.ts b/packages/toolpad-studio/src/utils/domView.ts
index 4dc75658206..76d1e8380f0 100644
--- a/packages/toolpad-studio/src/utils/domView.ts
+++ b/packages/toolpad-studio/src/utils/domView.ts
@@ -1,5 +1,5 @@
import { NodeId } from '@toolpad/studio-runtime';
-import { matchPath } from 'react-router-dom';
+import { matchPath } from 'react-router';
import { QueryNode, FetchMode } from '@toolpad/studio-runtime/appDom';
export type QueryMeta = {
diff --git a/playground/nextjs-pages/src/pages/_app.tsx b/playground/nextjs-pages/src/pages/_app.tsx
index 4efcb23d5d7..f6e5e6da068 100644
--- a/playground/nextjs-pages/src/pages/_app.tsx
+++ b/playground/nextjs-pages/src/pages/_app.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import { PageContainer } from '@toolpad/core/PageContainer';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import Head from 'next/head';
@@ -72,14 +72,14 @@ function AppLayout({ children }: { children: React.ReactNode }) {
-
{children}
-
+
);
}
diff --git a/playground/nextjs/src/app/layout.tsx b/playground/nextjs/src/app/layout.tsx
index 670a4c390dc..5944077d7f6 100644
--- a/playground/nextjs/src/app/layout.tsx
+++ b/playground/nextjs/src/app/layout.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { AppProvider } from '@toolpad/core/nextjs';
+import { NextAppProvider } from '@toolpad/core/nextjs';
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
@@ -41,14 +41,14 @@ export default async function RootLayout(props: { children: React.ReactNode }) {
-
{props.children}
-
+
diff --git a/playground/vite/package.json b/playground/vite/package.json
index 10333ecb496..a1c97054815 100644
--- a/playground/vite/package.json
+++ b/playground/vite/package.json
@@ -18,7 +18,7 @@
"@vitejs/plugin-react": "4.3.4",
"react": "18.3.1",
"react-dom": "18.3.1",
- "react-router-dom": "6.26.2",
+ "react-router": "7.1.0",
"vite": "5.4.11"
}
}
diff --git a/playground/vite/src/App.tsx b/playground/vite/src/App.tsx
index 2c6147c8788..ea7cb04796c 100644
--- a/playground/vite/src/App.tsx
+++ b/playground/vite/src/App.tsx
@@ -1,8 +1,9 @@
import * as React from 'react';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
-import { Outlet } from 'react-router-dom';
-import { AppProvider, type Navigation } from '@toolpad/core/react-router-dom';
+import { Outlet } from 'react-router';
+import { ReactRouterAppProvider } from '@toolpad/core/react-router';
+import type { Navigation } from '@toolpad/core/AppProvider';
const NAVIGATION: Navigation = [
{
@@ -26,8 +27,8 @@ const BRANDING = {
export default function App() {
return (
-
+
-
+
);
}
diff --git a/playground/vite/src/layouts/dashboard.tsx b/playground/vite/src/layouts/dashboard.tsx
index c540feb6e0f..84b8584f7c6 100644
--- a/playground/vite/src/layouts/dashboard.tsx
+++ b/playground/vite/src/layouts/dashboard.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { Outlet } from 'react-router-dom';
+import { Outlet } from 'react-router';
import { DashboardLayout } from '@toolpad/core/DashboardLayout';
import { PageContainer } from '@toolpad/core/PageContainer';
diff --git a/playground/vite/src/main.tsx b/playground/vite/src/main.tsx
index 882c91c0bff..cee7678c361 100644
--- a/playground/vite/src/main.tsx
+++ b/playground/vite/src/main.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
-import { createBrowserRouter, RouterProvider } from 'react-router-dom';
+import { createBrowserRouter, RouterProvider } from 'react-router';
import App from './App';
import Layout from './layouts/dashboard';
import DashboardPage from './pages';
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f193c84faa7..507276099b9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -455,8 +455,8 @@ importers:
specifier: 18.3.1
version: 18.3.1
react-router:
- specifier: 6.26.2
- version: 6.26.2(react@18.3.1)
+ specifier: 7.1.0
+ version: 7.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react-router-dom:
specifier: 6.26.2
version: 6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -671,9 +671,9 @@ importers:
playwright:
specifier: ^1.47.2
version: 1.48.2
- react-router-dom:
- specifier: 6.26.2
- version: 6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ react-router:
+ specifier: 7.1.0
+ version: 7.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
sinon:
specifier: ^19.0.2
version: 19.0.2
@@ -918,9 +918,9 @@ importers:
react-resizable-panels:
specifier: 2.1.7
version: 2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- react-router-dom:
- specifier: 6.26.2
- version: 6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ react-router:
+ specifier: 7.1.0
+ version: 7.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
semver:
specifier: 7.6.3
version: 7.6.3
@@ -1321,9 +1321,9 @@ importers:
react-dom:
specifier: 18.3.1
version: 18.3.1(react@18.3.1)
- react-router-dom:
- specifier: 6.26.2
- version: 6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ react-router:
+ specifier: 7.1.0
+ version: 7.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
vite:
specifier: 5.4.11
version: 5.4.11(@types/node@20.17.12)(terser@5.36.0)
@@ -9170,6 +9170,16 @@ packages:
peerDependencies:
react: '>=16.8'
+ react-router@7.1.0:
+ resolution: {integrity: sha512-VcFhWqkNIcojDRYaUO8qV0Jib52s9ULpCp3nkBbmrvtoCVFRp6tmk3tJ2w9BZauVctA1YRnJlFYDn9iJRuCpGA==}
+ engines: {node: '>=20.0.0'}
+ peerDependencies:
+ react: '>=18'
+ react-dom: '>=18'
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+
react-runner@1.0.5:
resolution: {integrity: sha512-eCIybRpssp6ffjqXqId024esO9UP2lV838Lvm3fC7VgMQ/dQHhR0jJwOY2IPrYD3AaM/bcvMikmASIRZqNUHsw==}
peerDependencies:
@@ -10198,6 +10208,9 @@ packages:
resolution: {integrity: sha512-GwIJau9XaA8nLVbUXsN3IlFi7WmQ48gBUrl3FTkkL/XLu/POhBzfmX9hd33FNMX1qAsfl6ozO1iMmW9NC8YniA==}
engines: {node: ^16.14.0 || >=18.0.0}
+ turbo-stream@2.4.0:
+ resolution: {integrity: sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==}
+
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@@ -19812,6 +19825,16 @@ snapshots:
'@remix-run/router': 1.19.2
react: 18.3.1
+ react-router@7.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ dependencies:
+ '@types/cookie': 0.6.0
+ cookie: 1.0.1
+ react: 18.3.1
+ set-cookie-parser: 2.7.1
+ turbo-stream: 2.4.0
+ optionalDependencies:
+ react-dom: 18.3.1(react@18.3.1)
+
react-runner@1.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
react: 18.3.1
@@ -21012,6 +21035,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ turbo-stream@2.4.0: {}
+
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
diff --git a/scripts/docs/buildCoreApiDocs/config/getComponentImports.ts b/scripts/docs/buildCoreApiDocs/config/getComponentImports.ts
index 7f1f29ebf29..7348f0141fa 100644
--- a/scripts/docs/buildCoreApiDocs/config/getComponentImports.ts
+++ b/scripts/docs/buildCoreApiDocs/config/getComponentImports.ts
@@ -3,6 +3,12 @@ import fs from 'fs';
const repositoryRoot = path.resolve(__dirname, '../../../..');
+function findMatchingFileName(directory: string, name: string) {
+ const files = fs.readdirSync(directory);
+ const matchingFile = files.find((file) => file.endsWith(name));
+ return matchingFile ? matchingFile.replace(/\.[^/.]+$/, '') : null; // Remove the extension
+}
+
export function getComponentImports(name: string, filename: string) {
const relativePath = path.relative(repositoryRoot, filename);
const directories = path.dirname(relativePath).split(path.sep);
@@ -21,18 +27,20 @@ export function getComponentImports(name: string, filename: string) {
const componentDirectory = directories[3];
if (componentDirectory === name) {
const nextjsRelativePath = path.resolve(relativePath, '../../nextjs');
- const hasNextJsVersion = fs.existsSync(`${nextjsRelativePath}/${name}.tsx`);
+ const nextjsFileName = findMatchingFileName(nextjsRelativePath, `${name}.tsx`);
- const reactRouterDOMRelativePath = path.resolve(relativePath, '../../react-router-dom');
- const hasReactRouterDOMVersion = fs.existsSync(`${reactRouterDOMRelativePath}/${name}.tsx`);
+ const reactRouterRelativePath = path.resolve(relativePath, '../../react-router');
+ const reactRouterFileName = findMatchingFileName(reactRouterRelativePath, `${name}.tsx`);
return [
`import { ${name} } from '@toolpad/core/${name}';`,
`import { ${name} } from '@toolpad/core';${
- hasNextJsVersion ? `\nimport { ${name} } from '@toolpad/core/nextjs'; // Next.js` : ''
+ nextjsFileName
+ ? `\nimport { ${nextjsFileName} } from '@toolpad/core/nextjs'; // Next.js`
+ : ''
}${
- hasReactRouterDOMVersion
- ? `\nimport { ${name} } from '@toolpad/core/react-router-dom'; // React Router`
+ reactRouterFileName
+ ? `\nimport { ${reactRouterFileName} } from '@toolpad/core/react-router'; // React Router`
: ''
}`,
];
diff --git a/scripts/docs/buildCoreApiDocs/config/projectSettings.ts b/scripts/docs/buildCoreApiDocs/config/projectSettings.ts
index 1702025b097..aa8de4fca9a 100644
--- a/scripts/docs/buildCoreApiDocs/config/projectSettings.ts
+++ b/scripts/docs/buildCoreApiDocs/config/projectSettings.ts
@@ -26,7 +26,7 @@ export const projectSettings: ProjectSettings = {
const relativePath = path.relative(repositoryRoot, filename);
const directories = path.dirname(relativePath).split(path.sep);
- return directories[3] === 'nextjs' || directories[3] === 'react-router-dom';
+ return directories[3] === 'nextjs' || directories[3] === 'react-router';
},
skipSlotsAndClasses: false,
translationPagesDirectory: 'docs/translations/api-docs',