Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core] Add toolbarActions and toolbarAccount slots to DashboardLayout #3984

Merged
merged 13 commits into from
Aug 29, 2024
21 changes: 20 additions & 1 deletion docs/pages/toolpad/core/api/dashboard-layout.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
{
"props": { "children": { "type": { "name": "node" }, "required": true } },
"props": {
"children": { "type": { "name": "node" }, "required": true },
"slotProps": {
"type": { "name": "shape", "description": "{ toolbarActions?: object }" },
"default": "{}"
},
"slots": {
"type": { "name": "shape", "description": "{ toolbarActions?: elementType }" },
"default": "{}",
"additionalInfo": { "slotsApi": true }
}
},
"name": "DashboardLayout",
"imports": [
"import { DashboardLayout } from '@toolpad/core/DashboardLayout';",
"import { DashboardLayout } from '@toolpad/core';"
],
"slots": [
{
"name": "toolbarActions",
"description": "The toolbar actions component used in the layout header.",
"default": "ToolbarActions",
"class": null
}
],
"classes": [],
"spread": true,
"themeDefaultProps": null,
Expand Down
32 changes: 32 additions & 0 deletions docs/pages/toolpad/core/api/sign-in-page.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,38 @@
"import { SignInPage } from '@toolpad/core/SignInPage';",
"import { SignInPage } from '@toolpad/core';"
],
"slots": [
{
"name": "emailField",
"description": "The custom email field component used in the credentials form.",
"default": "TextField",
"class": null
},
{
"name": "passwordField",
"description": "The custom password field component used in the credentials form.",
"default": "TextField",
"class": null
},
{
"name": "submitButton",
"description": "The custom submit button component used in the credentials form.",
"default": "LoadingButton",
"class": null
},
{
"name": "forgotPasswordLink",
"description": "The custom forgot password link component used in the credentials form.",
"default": "Link",
"class": null
},
{
"name": "signUpLink",
"description": "The custom sign up link component used in the credentials form.",
"default": "Link",
"class": null
}
],
"classes": [],
"spread": true,
"themeDefaultProps": false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
{
"componentDescription": "",
"propDescriptions": { "children": { "description": "The content of the dashboard." } },
"classDescriptions": {}
"propDescriptions": {
"children": { "description": "The content of the dashboard." },
"slotProps": { "description": "The props used for each slot inside." },
"slots": { "description": "The components used for each slot inside." }
},
"classDescriptions": {},
"slotDescriptions": {
"toolbarActions": "The toolbar actions component used in the layout header."
}
}
9 changes: 8 additions & 1 deletion docs/translations/api-docs/sign-in-page/sign-in-page.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,12 @@
"slotProps": { "description": "The props used for each slot inside." },
"slots": { "description": "The components used for each slot inside." }
},
"classDescriptions": {}
"classDescriptions": {},
"slotDescriptions": {
"emailField": "The custom email field component used in the credentials form.",
"forgotPasswordLink": "The custom forgot password link component used in the credentials form.",
"passwordField": "The custom password field component used in the credentials form.",
"signUpLink": "The custom sign up link component used in the credentials form.",
"submitButton": "The custom submit button component used in the credentials form."
}
}
4 changes: 2 additions & 2 deletions packages/toolpad-core/src/AppProvider/AppProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ export interface Authentication {
signOut: () => void;
}

export const SessionContext = React.createContext<Session | null>(null);

export const AuthenticationContext = React.createContext<Authentication | null>(null);

export const SessionContext = React.createContext<Session | null>(null);

export type AppTheme = Theme | { light: Theme; dark: Theme };

export interface AppProviderProps {
Expand Down
110 changes: 43 additions & 67 deletions packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
import { styled, useTheme } from '@mui/material';
import { styled } from '@mui/material';
import MuiAppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box';
import Collapse from '@mui/material/Collapse';
Expand All @@ -19,23 +19,20 @@ import Toolbar from '@mui/material/Toolbar';
import Tooltip from '@mui/material/Tooltip';
import Typography from '@mui/material/Typography';
import type {} from '@mui/material/themeCssVarsAugmentation';
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 { Account } from '../Account';
import { Link } from '../shared/Link';
import {
BrandingContext,
NavigationContext,
PaletteModeContext,
RouterContext,
WindowContext,
} from '../shared/context';
import type { Navigation } from '../AppProvider';
import { ThemeSwitcher } from './ThemeSwitcher';
import { ToolbarActions } from './ToolbarActions';
import { ToolpadLogo } from './ToolpadLogo';
import {
getItemTitle,
Expand Down Expand Up @@ -86,65 +83,6 @@ const NavigationListItemButton = styled(ListItemButton)(({ theme }) => ({
},
}));

function ThemeSwitcher() {
const isSsr = useSsr();
const theme = useTheme();

const { paletteMode, setPaletteMode, isDualTheme } = React.useContext(PaletteModeContext);

const toggleMode = React.useCallback(() => {
setPaletteMode(paletteMode === 'dark' ? 'light' : 'dark');
}, [paletteMode, setPaletteMode]);

return isDualTheme ? (
<Tooltip
title={isSsr ? 'Switch mode' : `${paletteMode === 'dark' ? 'Light' : 'Dark'} mode`}
enterDelay={1000}
>
<div>
<IconButton
aria-label={
isSsr
? 'Switch theme mode'
: `Switch to ${paletteMode === 'dark' ? 'light' : 'dark'} mode`
}
onClick={toggleMode}
sx={{
color: (theme.vars ?? theme).palette.primary.dark,
padding: 1,
marginRight: 1,
}}
>
{theme.getColorSchemeSelector ? (
<React.Fragment>
<DarkModeIcon
sx={{
display: 'inline',
[theme.getColorSchemeSelector('dark')]: {
display: 'none',
},
}}
/>
<LightModeIcon
sx={{
display: 'none',
[theme.getColorSchemeSelector('dark')]: {
display: 'inline',
},
}}
/>
</React.Fragment>
) : (
<React.Fragment>
{isSsr || paletteMode !== 'dark' ? <DarkModeIcon /> : <LightModeIcon />}
</React.Fragment>
)}
</IconButton>
</div>
</Tooltip>
) : null;
}

interface DashboardSidebarSubNavigationProps {
subNavigation: Navigation;
basePath?: string;
Expand Down Expand Up @@ -313,11 +251,31 @@ function DashboardSidebarSubNavigation({
);
}

export interface DashboardLayoutSlots {
/**
* The toolbar actions component used in the layout header.
* @default ToolbarActions
*/
toolbarActions?: React.JSXElementConstructor<{}>;
}

export interface DashboardLayoutProps {
/**
* The content of the dashboard.
*/
children: React.ReactNode;
/**
* The components used for each slot inside.
* @default {}
*/
slots?: DashboardLayoutSlots;
/**
* The props used for each slot inside.
* @default {}
*/
slotProps?: {
toolbarActions?: {};
};
}

/**
Expand All @@ -331,7 +289,7 @@ export interface DashboardLayoutProps {
* - [DashboardLayout API](https://mui.com/toolpad/core/api/dashboard-layout)
*/
function DashboardLayout(props: DashboardLayoutProps) {
const { children } = props;
const { children, slots, slotProps } = props;

const branding = React.useContext(BrandingContext);
const navigation = React.useContext(NavigationContext);
Expand Down Expand Up @@ -429,7 +387,11 @@ function DashboardLayout(props: DashboardLayoutProps) {
</Box>
<Box sx={{ flexGrow: 1 }} />
<ThemeSwitcher />
<Account />
{slots?.toolbarActions ? (
<slots.toolbarActions {...slotProps?.toolbarActions} />
) : (
<ToolbarActions {...slotProps?.toolbarActions} />
)}
</Toolbar>
</AppBar>
<Drawer
Expand Down Expand Up @@ -493,6 +455,20 @@ DashboardLayout.propTypes /* remove-proptypes */ = {
* The content of the dashboard.
*/
children: PropTypes.node,
/**
* The props used for each slot inside.
* @default {}
*/
slotProps: PropTypes.shape({
toolbarActions: PropTypes.object,
}),
/**
* The components used for each slot inside.
* @default {}
*/
slots: PropTypes.shape({
toolbarActions: PropTypes.elementType,
}),
} as any;

export { DashboardLayout };
73 changes: 73 additions & 0 deletions packages/toolpad-core/src/DashboardLayout/ThemeSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
'use client';
import * as React from 'react';
import { useTheme } from '@mui/material';
import IconButton from '@mui/material/IconButton';
import Tooltip from '@mui/material/Tooltip';
import DarkModeIcon from '@mui/icons-material/DarkMode';
import LightModeIcon from '@mui/icons-material/LightMode';
import useSsr from '@toolpad/utils/hooks/useSsr';
import { PaletteModeContext } from '../shared/context';

/**
* @ignore - internal component.
*/
function ThemeSwitcher() {
const isSsr = useSsr();
const theme = useTheme();

const { paletteMode, setPaletteMode, isDualTheme } = React.useContext(PaletteModeContext);

const toggleMode = React.useCallback(() => {
setPaletteMode(paletteMode === 'dark' ? 'light' : 'dark');
}, [paletteMode, setPaletteMode]);

return isDualTheme ? (
<Tooltip
title={isSsr ? 'Switch mode' : `${paletteMode === 'dark' ? 'Light' : 'Dark'} mode`}
enterDelay={1000}
>
<div>
<IconButton
aria-label={
isSsr
? 'Switch theme mode'
: `Switch to ${paletteMode === 'dark' ? 'light' : 'dark'} mode`
}
onClick={toggleMode}
sx={{
color: (theme.vars ?? theme).palette.primary.dark,
padding: 1,
marginRight: 1,
}}
>
{theme.getColorSchemeSelector ? (
<React.Fragment>
<DarkModeIcon
sx={{
display: 'inline',
[theme.getColorSchemeSelector('dark')]: {
display: 'none',
},
}}
/>
<LightModeIcon
sx={{
display: 'none',
[theme.getColorSchemeSelector('dark')]: {
display: 'inline',
},
}}
/>
</React.Fragment>
) : (
<React.Fragment>
{isSsr || paletteMode !== 'dark' ? <DarkModeIcon /> : <LightModeIcon />}
</React.Fragment>
)}
</IconButton>
</div>
</Tooltip>
) : null;
}

export { ThemeSwitcher };
12 changes: 12 additions & 0 deletions packages/toolpad-core/src/DashboardLayout/ToolbarActions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use client';
import * as React from 'react';
import { Account } from '../Account';

/**
* @ignore - internal component.
*/
function ToolbarActions() {
Copy link
Member Author

@apedroferreira apedroferreira Aug 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Placeholder component for later, but could just be null directly too.

return <Account />;
}

export { ToolbarActions };
3 changes: 3 additions & 0 deletions packages/toolpad-core/src/DashboardLayout/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export * from './DashboardLayout';

// Default slots components
export * from './ToolbarActions';
Loading
Loading