diff --git a/docs/data/toolpad/core/components/app-provider/AppProviderBasic.js b/docs/data/toolpad/core/components/app-provider/AppProviderBasic.js index 7facac0f5e0..c248277a86e 100644 --- a/docs/data/toolpad/core/components/app-provider/AppProviderBasic.js +++ b/docs/data/toolpad/core/components/app-provider/AppProviderBasic.js @@ -2,6 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; import DashboardIcon from '@mui/icons-material/Dashboard'; import TimelineIcon from '@mui/icons-material/Timeline'; import { AppProvider } from '@toolpad/core/AppProvider'; @@ -24,6 +25,18 @@ const NAVIGATION = [ }, ]; +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + function DemoPageContent({ pathname }) { return ( + diff --git a/docs/data/toolpad/core/components/app-provider/AppProviderBasic.tsx b/docs/data/toolpad/core/components/app-provider/AppProviderBasic.tsx index 07db300713b..c5b29991d45 100644 --- a/docs/data/toolpad/core/components/app-provider/AppProviderBasic.tsx +++ b/docs/data/toolpad/core/components/app-provider/AppProviderBasic.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; import DashboardIcon from '@mui/icons-material/Dashboard'; import TimelineIcon from '@mui/icons-material/Timeline'; import { AppProvider } from '@toolpad/core/AppProvider'; @@ -24,6 +25,18 @@ const NAVIGATION: Navigation = [ }, ]; +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + function DemoPageContent({ pathname }: { pathname: string }) { return ( + diff --git a/docs/data/toolpad/core/components/app-provider/AppProviderBasic.tsx.preview b/docs/data/toolpad/core/components/app-provider/AppProviderBasic.tsx.preview index 512dc89fa09..2f597acc500 100644 --- a/docs/data/toolpad/core/components/app-provider/AppProviderBasic.tsx.preview +++ b/docs/data/toolpad/core/components/app-provider/AppProviderBasic.tsx.preview @@ -1,4 +1,9 @@ - + diff --git a/docs/data/toolpad/core/components/app-provider/AppProviderTheme.js b/docs/data/toolpad/core/components/app-provider/AppProviderTheme.js index 6eea396cf0d..36b215727fe 100644 --- a/docs/data/toolpad/core/components/app-provider/AppProviderTheme.js +++ b/docs/data/toolpad/core/components/app-provider/AppProviderTheme.js @@ -44,6 +44,15 @@ const customTheme = extendTheme({ }, }, }, + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, }); function DemoPageContent({ pathname }) { diff --git a/docs/data/toolpad/core/components/app-provider/AppProviderTheme.tsx b/docs/data/toolpad/core/components/app-provider/AppProviderTheme.tsx index ec6ac7500c6..e034fea0b92 100644 --- a/docs/data/toolpad/core/components/app-provider/AppProviderTheme.tsx +++ b/docs/data/toolpad/core/components/app-provider/AppProviderTheme.tsx @@ -44,6 +44,15 @@ const customTheme = extendTheme({ }, }, }, + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, }); function DemoPageContent({ pathname }: { pathname: string }) { diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.js b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.js index 6881d21974e..cd8849dda52 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.js +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.js @@ -2,6 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; import DashboardIcon from '@mui/icons-material/Dashboard'; import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; import BarChartIcon from '@mui/icons-material/BarChart'; @@ -56,6 +57,18 @@ const NAVIGATION = [ }, ]; +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + function DemoPageContent({ pathname }) { return ( + diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.tsx b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.tsx index 587d3da4410..81bbe91c18a 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.tsx +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; import DashboardIcon from '@mui/icons-material/Dashboard'; import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; import BarChartIcon from '@mui/icons-material/BarChart'; @@ -56,6 +57,18 @@ const NAVIGATION: Navigation = [ }, ]; +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + function DemoPageContent({ pathname }: { pathname: string }) { return ( + diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.tsx.preview b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.tsx.preview index 512dc89fa09..2f597acc500 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.tsx.preview +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBasic.tsx.preview @@ -1,4 +1,9 @@ - + diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.js b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.js index 522fb7c5630..f1e888bcc51 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.js +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.js @@ -2,6 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; import DashboardIcon from '@mui/icons-material/Dashboard'; import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; import { AppProvider } from '@toolpad/core/AppProvider'; @@ -20,6 +21,18 @@ const NAVIGATION = [ }, ]; +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + function DemoPageContent({ pathname }) { return ( diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.tsx b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.tsx index 0aa5b5bb398..c607a9bcb77 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.tsx +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; import DashboardIcon from '@mui/icons-material/Dashboard'; import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; import { AppProvider, Router } from '@toolpad/core/AppProvider'; @@ -20,6 +21,18 @@ const NAVIGATION: Navigation = [ }, ]; +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + function DemoPageContent({ pathname }: { pathname: string }) { return ( diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.tsx.preview b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.tsx.preview index f33054ed6a1..f47143bf17f 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.tsx.preview +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutBranding.tsx.preview @@ -5,6 +5,7 @@ title: 'MUI', }} router={router} + theme={demoTheme} window={demoWindow} > diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.js b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.js index acf465c3987..b52f13b5c3e 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.js +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.js @@ -2,11 +2,24 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; import DescriptionIcon from '@mui/icons-material/Description'; import FolderIcon from '@mui/icons-material/Folder'; import { AppProvider } from '@toolpad/core/AppProvider'; import { DashboardLayout } from '@toolpad/core/DashboardLayout'; +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + function DemoPageContent({ pathname }) { return ( diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.tsx b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.tsx index 829c9d59613..524425e591b 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.tsx +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.tsx @@ -1,11 +1,24 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; import DescriptionIcon from '@mui/icons-material/Description'; import FolderIcon from '@mui/icons-material/Folder'; import { AppProvider, Router } from '@toolpad/core/AppProvider'; import { DashboardLayout } from '@toolpad/core/DashboardLayout'; +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + function DemoPageContent({ pathname }: { pathname: string }) { return ( diff --git a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.tsx.preview b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.tsx.preview index b45308001d4..4e170236a40 100644 --- a/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.tsx.preview +++ b/docs/data/toolpad/core/components/dashboard-layout/DashboardLayoutNavigation.tsx.preview @@ -140,6 +140,7 @@ }, ]} router={router} + theme={demoTheme} window={demoWindow} > diff --git a/docs/data/toolpad/core/introduction/TutorialDefault.js b/docs/data/toolpad/core/introduction/TutorialDefault.js index f825efce79f..3329764f906 100644 --- a/docs/data/toolpad/core/introduction/TutorialDefault.js +++ b/docs/data/toolpad/core/introduction/TutorialDefault.js @@ -2,6 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; import DashboardIcon from '@mui/icons-material/Dashboard'; import { AppProvider } from '@toolpad/core/AppProvider'; import { DashboardLayout } from '@toolpad/core/DashboardLayout'; @@ -13,6 +14,18 @@ const NAVIGATION = [ }, ]; +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + function DemoPageContent() { return ( + diff --git a/docs/data/toolpad/core/introduction/TutorialDefault.tsx b/docs/data/toolpad/core/introduction/TutorialDefault.tsx index e9eb39d63f1..b9240242191 100644 --- a/docs/data/toolpad/core/introduction/TutorialDefault.tsx +++ b/docs/data/toolpad/core/introduction/TutorialDefault.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; import DashboardIcon from '@mui/icons-material/Dashboard'; import { AppProvider, Navigation } from '@toolpad/core/AppProvider'; import { DashboardLayout } from '@toolpad/core/DashboardLayout'; @@ -12,6 +13,18 @@ const NAVIGATION: Navigation = [ }, ]; +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + function DemoPageContent() { return ( + diff --git a/docs/data/toolpad/core/introduction/TutorialPages.js b/docs/data/toolpad/core/introduction/TutorialPages.js index 163b82a75f6..1b8a25c8fae 100644 --- a/docs/data/toolpad/core/introduction/TutorialPages.js +++ b/docs/data/toolpad/core/introduction/TutorialPages.js @@ -2,6 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; import DashboardIcon from '@mui/icons-material/Dashboard'; import TimelineIcon from '@mui/icons-material/Timeline'; import { AppProvider } from '@toolpad/core/AppProvider'; @@ -25,6 +26,18 @@ const NAVIGATION = [ }, ]; +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + function DemoPageContent({ pathname }) { return ( + diff --git a/docs/data/toolpad/core/introduction/TutorialPages.tsx b/docs/data/toolpad/core/introduction/TutorialPages.tsx index dff3830a32c..e8a27211cf1 100644 --- a/docs/data/toolpad/core/introduction/TutorialPages.tsx +++ b/docs/data/toolpad/core/introduction/TutorialPages.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; +import { extendTheme } from '@mui/material/styles'; import DashboardIcon from '@mui/icons-material/Dashboard'; import TimelineIcon from '@mui/icons-material/Timeline'; import { AppProvider, Navigation, Router } from '@toolpad/core/AppProvider'; @@ -24,6 +25,18 @@ const NAVIGATION: Navigation = [ }, ]; +const demoTheme = extendTheme({ + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 600, + lg: 1200, + xl: 1536, + }, + }, +}); + function DemoPageContent({ pathname }: { pathname: string }) { return ( + diff --git a/packages/toolpad-core/src/AppProvider/AppProvider.tsx b/packages/toolpad-core/src/AppProvider/AppProvider.tsx index 4492e72850f..1a2e8f88ba3 100644 --- a/packages/toolpad-core/src/AppProvider/AppProvider.tsx +++ b/packages/toolpad-core/src/AppProvider/AppProvider.tsx @@ -4,7 +4,12 @@ import PropTypes from 'prop-types'; import { extendTheme, CssVarsTheme, Theme } from '@mui/material/styles'; import { NotificationsProvider } from '../useNotifications'; import { DialogsProvider } from '../useDialogs'; -import { BrandingContext, NavigationContext, RouterContext } from '../shared/context'; +import { + BrandingContext, + NavigationContext, + RouterContext, + WindowContext, +} from '../shared/context'; import { AppThemeProvider } from './AppThemeProvider'; export interface NavigateOptions { @@ -101,21 +106,25 @@ function AppProvider(props: AppProviderProps) { branding = null, navigation = [], router = null, - window, + window: appWindow, } = props; return ( - - - - - - {children} - - - - - + + + + + + + + {children} + + + + + + + ); } diff --git a/packages/toolpad-core/src/AppProvider/AppThemeProvider.tsx b/packages/toolpad-core/src/AppProvider/AppThemeProvider.tsx index 841ca8a428d..116445ac100 100644 --- a/packages/toolpad-core/src/AppProvider/AppThemeProvider.tsx +++ b/packages/toolpad-core/src/AppProvider/AppThemeProvider.tsx @@ -109,7 +109,7 @@ interface CSSVarsThemeProviderProps { * @ignore - internal component. */ function CSSVarsThemeProvider(props: CSSVarsThemeProviderProps) { - const { children, theme, window } = props; + const { children, theme, window: appWindow } = props; const isDualTheme = 'light' in theme.colorSchemes && 'dark' in theme.colorSchemes; @@ -117,8 +117,8 @@ function CSSVarsThemeProvider(props: CSSVarsThemeProviderProps) { {children} @@ -135,7 +135,7 @@ interface AppThemeProviderProps { * @ignore - internal component. */ function AppThemeProvider(props: AppThemeProviderProps) { - const { children, theme, window } = props; + const { children, theme, window: appWindow } = props; const isCSSVarsTheme = 'colorSchemes' in theme; @@ -149,7 +149,7 @@ function AppThemeProvider(props: AppThemeProviderProps) { return isCSSVarsTheme ? ( - + {themeChildren} diff --git a/packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx b/packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx index 18e58e76c35..b2af7be0b2c 100644 --- a/packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx +++ b/packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx @@ -24,17 +24,20 @@ import DarkModeIcon from '@mui/icons-material/DarkMode'; import LightModeIcon from '@mui/icons-material/LightMode'; import ExpandLessIcon from '@mui/icons-material/ExpandLess'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import MenuIcon from '@mui/icons-material/Menu'; +import MenuOpenIcon from '@mui/icons-material/MenuOpen'; import useSsr from '@toolpad/utils/hooks/useSsr'; import { BrandingContext, NavigationContext, PaletteModeContext, RouterContext, + WindowContext, } from '../shared/context'; import type { Navigation, NavigationPageItem } from '../AppProvider'; import { ToolpadLogo } from './ToolpadLogo'; -const DRAWER_WIDTH = 320; +const DRAWER_WIDTH = 320; // px const AppBar = styled(MuiAppBar)(({ theme }) => ({ backgroundColor: (theme.vars ?? theme).palette.background.paper, @@ -137,12 +140,14 @@ interface DashboardSidebarSubNavigationProps { subNavigation: Navigation; basePath?: string; depth?: number; + onSidebarItemClick?: (item: NavigationPageItem) => void; } function DashboardSidebarSubNavigation({ subNavigation, basePath = '', depth = 0, + onSidebarItemClick, }: DashboardSidebarSubNavigationProps) { const routerContext = React.useContext(RouterContext); @@ -177,14 +182,20 @@ function DashboardSidebarSubNavigation({ ); const handleSidebarItemClick = React.useCallback( - (itemId: string) => () => { - setExpandedSidebarItemIds((previousValue) => - previousValue.includes(itemId) - ? previousValue.filter((previousValueItemId) => previousValueItemId !== itemId) - : [...previousValue, itemId], - ); + (itemId: string, item: NavigationPageItem) => () => { + if (item.children) { + setExpandedSidebarItemIds((previousValue) => + previousValue.includes(itemId) + ? previousValue.filter((previousValueItemId) => previousValueItemId !== itemId) + : [...previousValue, itemId], + ); + } + + if (onSidebarItemClick) { + onSidebarItemClick(item); + } }, - [], + [onSidebarItemClick], ); const handleLinkClick = React.useMemo(() => { @@ -251,15 +262,17 @@ function DashboardSidebarSubNavigation({ - - {navigationItem.icon} - + {navigationItem.icon ? ( + + {navigationItem.icon} + + ) : null} ) : null} @@ -325,49 +339,123 @@ function DashboardLayout(props: DashboardLayoutProps) { const branding = React.useContext(BrandingContext); const navigation = React.useContext(NavigationContext); + const appWindow = React.useContext(WindowContext); + + const [isMobileNavigationOpen, setIsMobileNavigationOpen] = React.useState(false); + + const handleSetMobileNavigationOpen = React.useCallback( + (newOpen: boolean) => () => { + setIsMobileNavigationOpen(newOpen); + }, + [], + ); + + const toggleMobileNavigation = React.useCallback(() => { + setIsMobileNavigationOpen((previousOpen) => !previousOpen); + }, []); + + const handleNavigationItemClick = React.useCallback((item: NavigationPageItem) => { + if (!item.children) { + setIsMobileNavigationOpen(false); + } + }, []); + + const drawerContent = ( + + + + + + + ); return ( - - - + + +
+ + {isMobileNavigationOpen ? : } + +
+
+
+ +
+ {branding?.logo ?? } -
- (theme.vars ?? theme).palette.primary.main, - fontWeight: '700', - }} - > - {branding?.title ?? 'Toolpad'} - - - + (theme.vars ?? theme).palette.primary.main, + fontWeight: '700', + }} + > + {branding?.title ?? 'Toolpad'} + + + +
+ `1px solid ${(theme.vars ?? theme).palette.divider}`, + }, + }} + > + {drawerContent} + - - - - + {drawerContent} diff --git a/packages/toolpad-core/src/shared/context.ts b/packages/toolpad-core/src/shared/context.ts index 9a75b58dda3..0b3a25323c3 100644 --- a/packages/toolpad-core/src/shared/context.ts +++ b/packages/toolpad-core/src/shared/context.ts @@ -17,3 +17,5 @@ export const PaletteModeContext = React.createContext<{ }); export const RouterContext = React.createContext(null); + +export const WindowContext = React.createContext(undefined); diff --git a/packages/toolpad-core/vitest.config.mts b/packages/toolpad-core/vitest.config.mts index 1013f7aa976..12919d3730b 100644 --- a/packages/toolpad-core/vitest.config.mts +++ b/packages/toolpad-core/vitest.config.mts @@ -8,6 +8,10 @@ export default defineConfig({ name: 'chromium', provider: 'playwright', headless: !!process.env.CI, + viewport: { + width: 1024, + height: 896, + }, }, coverage: { exclude: ['./build/**'],