Skip to content

Commit

Permalink
[docs] Improve Toolpad Core docs (#43796)
Browse files Browse the repository at this point in the history
  • Loading branch information
bharatkashyap authored Oct 15, 2024
1 parent bd3bc3b commit 1719ed4
Show file tree
Hide file tree
Showing 19 changed files with 479 additions and 156 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export default function DashboardLayoutBasic(props) {
const router = useDemoRouter('/dashboard');

// Remove this const when copying and pasting into your project.
const demoWindow = window !== undefined ? window() : undefined;
const demoWindow = window ? window() : undefined;

return (
<AppProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export default function DashboardLayoutBasic(props: any) {
const router = useDemoRouter('/dashboard');

// Remove this const when copying and pasting into your project.
const demoWindow = window !== undefined ? window() : undefined;
const demoWindow = window ? window() : undefined;

return (
<AppProvider
Expand Down
6 changes: 3 additions & 3 deletions docs/data/material/components/app-bar/app-bar.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ You can override this behavior by setting the `enableColorOnDark` prop to `true`

{{"demo": "EnableColorOnDarkAppBar.js", "bg": true}}

## Experimental APIs
## Toolpad (Beta)

### DashboardLayout
### Dashboard Layout

The [DashboardLayout](https://mui.com/toolpad/core/react-dashboard-layout/) component from `@toolpad/core` is the starting point for dashboarding applications. It takes care of application layout, theming, navigation, and more. An example usage of this component:

{{"demo": "DashboardLayoutBasic.js", "height": 400, "iframe": true, "hideToolbar": true}}
{{"demo": "DashboardLayoutBasic.js", "height": 400, "iframe": true, "bg": "inline", "defaultExpanded": false}}
22 changes: 4 additions & 18 deletions docs/data/material/components/breadcrumbs/PageContainerBasic.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { extendTheme, styled } from '@mui/material/styles';
import { styled, useTheme } from '@mui/material/styles';
import DashboardIcon from '@mui/icons-material/Dashboard';
import { AppProvider } from '@toolpad/core/AppProvider';
import { PageContainer, PageContainerToolbar } from '@toolpad/core/PageContainer';
Expand All @@ -18,20 +18,6 @@ const NAVIGATION = [
},
];

const demoTheme = extendTheme({
colorSchemes: { light: true, dark: true },
colorSchemeSelector: 'class',
breakpoints: {
values: {
xs: 0,
sm: 600,
md: 600,
lg: 1200,
xl: 1536,
},
},
});

function useDemoRouter(initialPath) {
const [pathname, setPathname] = React.useState(initialPath);

Expand Down Expand Up @@ -81,15 +67,15 @@ function PageToolbar() {
export default function PageContainerBasic(props) {
const { window } = props;
const router = useDemoRouter('/orders');

const theme = useTheme();
// Remove this const when copying and pasting into your project.
const demoWindow = window !== undefined ? window() : undefined;
const demoWindow = window ? window() : undefined;

return (
<AppProvider
navigation={NAVIGATION}
router={router}
theme={demoTheme}
theme={theme}
window={demoWindow}
branding={{
title: 'ACME Inc.',
Expand Down
22 changes: 4 additions & 18 deletions docs/data/material/components/breadcrumbs/PageContainerBasic.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { extendTheme, styled } from '@mui/material/styles';
import { styled, useTheme } from '@mui/material/styles';
import DashboardIcon from '@mui/icons-material/Dashboard';
import { AppProvider, Navigation, Router } from '@toolpad/core/AppProvider';
import { PageContainer, PageContainerToolbar } from '@toolpad/core/PageContainer';
Expand All @@ -18,20 +18,6 @@ const NAVIGATION: Navigation = [
},
];

const demoTheme = extendTheme({
colorSchemes: { light: true, dark: true },
colorSchemeSelector: 'class',
breakpoints: {
values: {
xs: 0,
sm: 600,
md: 600,
lg: 1200,
xl: 1536,
},
},
});

function useDemoRouter(initialPath: string): Router {
const [pathname, setPathname] = React.useState(initialPath);

Expand Down Expand Up @@ -81,15 +67,15 @@ function PageToolbar() {
export default function PageContainerBasic(props: any) {
const { window } = props;
const router = useDemoRouter('/orders');

const theme = useTheme();
// Remove this const when copying and pasting into your project.
const demoWindow = window !== undefined ? window() : undefined;
const demoWindow = window ? window() : undefined;

return (
<AppProvider
navigation={NAVIGATION}
router={router}
theme={demoTheme}
theme={theme}
window={demoWindow}
branding={{
title: 'ACME Inc.',
Expand Down
6 changes: 3 additions & 3 deletions docs/data/material/components/breadcrumbs/breadcrumbs.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ The accessibility of this component relies on:
- To prevent screen reader announcement of the visual separators between links, they are hidden with `aria-hidden`.
- A nav element labeled with `aria-label` identifies the structure as a breadcrumb trail and makes it a navigation landmark so that it is easy to locate.

## Experimental APIs
## Toolpad (Beta)

### Page Container

The [PageContainer](https://mui.com/toolpad/core/react-page-container/) component in `@toolpad/core` is the ideal wrapper for the content of your dashboard. It makes the Material UI Container navigation aware and extends it with page title, breadcrumbs, actions, and more.
The [PageContainer](https://mui.com/toolpad/core/react-page-container/) component in `@toolpad/core` is the ideal wrapper for the content of your dashboard. It makes the Material UI Container navigation-aware and extends it with page title, breadcrumbs, actions, and more.

{{"demo": "./PageContainerBasic.js", "height": 400, "hideToolbar": true}}
{{"demo": "PageContainerBasic.js", "height": 400, "bg": "inline", "defaultExpanded": false}}
6 changes: 3 additions & 3 deletions docs/data/material/components/container/container.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ The max-width matches the min-width of the current breakpoint.
<Container fixed>
```

## Experimental APIs
## Toolpad (Beta)

### Page Container

The [PageContainer](https://mui.com/toolpad/core/react-page-container/) component in `@toolpad/core` is the ideal wrapper for the content of your dashboard. It makes the Material UI Container navigation aware and extends it with page title, breadcrumbs, actions, and more.
The [PageContainer](https://mui.com/toolpad/core/react-page-container/) component in `@toolpad/core` is the ideal wrapper for the content of your dashboard. It makes the Material UI Container navigation-aware and extends it with page title, breadcrumbs, actions, and more.

{{"demo": "../breadcrumbs/PageContainerBasic.js", "height": 400, "hideToolbar": true}}
{{"demo": "../breadcrumbs/PageContainerBasic.js", "height": 400, "bg": "inline", "defaultExpanded": false}}
120 changes: 120 additions & 0 deletions docs/data/material/components/dialogs/ToolpadDialogsNoSnap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { DialogsProvider, useDialogs } from '@toolpad/core/useDialogs';
import Button from '@mui/material/Button';
import LoadingButton from '@mui/lab/LoadingButton';
import Dialog from '@mui/material/Dialog';
import Alert from '@mui/material/Alert';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import DialogActions from '@mui/material/DialogActions';

function MyCustomDialog({ open, onClose, payload }) {
return (
<Dialog fullWidth open={open} onClose={() => onClose()}>
<DialogTitle>Custom Error Handler</DialogTitle>
<DialogContent>
<Alert severity="error">
{`An error occurred while deleting item "${payload.id}":`}
<pre>{payload.error}</pre>
</Alert>
</DialogContent>
<DialogActions>
<Button onClick={() => onClose()}>Close me</Button>
</DialogActions>
</Dialog>
);
}

MyCustomDialog.propTypes = {
/**
* A function to call when the dialog should be closed. If the dialog has a return
* value, it should be passed as an argument to this function. You should use the promise
* that is returned to show a loading state while the dialog is performing async actions
* on close.
* @param result The result to return from the dialog.
* @returns A promise that resolves when the dialog can be fully closed.
*/
onClose: PropTypes.func.isRequired,
/**
* Whether the dialog is open.
*/
open: PropTypes.bool.isRequired,
/**
* The payload that was passed when the dialog was opened.
*/
payload: PropTypes.shape({
error: PropTypes.string,
id: PropTypes.string,
}).isRequired,
};

const mockApiDelete = async (id) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (!id) {
reject(new Error('ID is required'));
} else if (parseInt(id, 10) % 2 === 0) {
console.log('id', parseInt(id, 10));
resolve(true);
} else if (parseInt(id, 10) % 2 === 1) {
reject(new Error('Can not delete odd numbered elements'));
} else if (Number.isNaN(parseInt(id, 10))) {
reject(new Error('ID must be a number'));
} else {
reject(new Error('Unknown error'));
}
}, 1000);
});
};

function DemoContent() {
const dialogs = useDialogs();
const [isDeleting, setIsDeleting] = React.useState(false);

const handleDelete = async () => {
const id = await dialogs.prompt('Enter the ID to delete', {
okText: 'Delete',
cancelText: 'Cancel',
});

if (id) {
const deleteConfirmed = await dialogs.confirm(
`Are you sure you want to delete "${id}"?`,
);
if (deleteConfirmed) {
try {
setIsDeleting(true);
await mockApiDelete(id);
dialogs.alert('Deleted!');
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
await dialogs.open(MyCustomDialog, { id, error: message });
} finally {
setIsDeleting(false);
}
}
}
};
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
<div style={{ display: 'flex', gap: 16 }}>
<LoadingButton
variant="contained"
loading={isDeleting}
onClick={handleDelete}
>
Delete
</LoadingButton>
</div>
</div>
);
}

export default function ToolpadDialogsNoSnap() {
return (
<DialogsProvider>
<DemoContent />
</DialogsProvider>
);
}
101 changes: 101 additions & 0 deletions docs/data/material/components/dialogs/ToolpadDialogsNoSnap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import * as React from 'react';
import { DialogsProvider, useDialogs, DialogProps } from '@toolpad/core/useDialogs';
import Button from '@mui/material/Button';
import LoadingButton from '@mui/lab/LoadingButton';
import Dialog from '@mui/material/Dialog';
import Alert from '@mui/material/Alert';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import DialogActions from '@mui/material/DialogActions';

interface DeleteError {
id: string | null;
error: string | null;
}

function MyCustomDialog({ open, onClose, payload }: DialogProps<DeleteError>) {
return (
<Dialog fullWidth open={open} onClose={() => onClose()}>
<DialogTitle>Custom Error Handler</DialogTitle>
<DialogContent>
<Alert severity="error">
{`An error occurred while deleting item "${payload.id}":`}
<pre>{payload.error}</pre>
</Alert>
</DialogContent>
<DialogActions>
<Button onClick={() => onClose()}>Close me</Button>
</DialogActions>
</Dialog>
);
}

const mockApiDelete = async (id: string | null) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (!id) {
reject(new Error('ID is required'));
} else if (parseInt(id, 10) % 2 === 0) {
console.log('id', parseInt(id, 10));
resolve(true);
} else if (parseInt(id, 10) % 2 === 1) {
reject(new Error('Can not delete odd numbered elements'));
} else if (Number.isNaN(parseInt(id, 10))) {
reject(new Error('ID must be a number'));
} else {
reject(new Error('Unknown error'));
}
}, 1000);
});
};

function DemoContent() {
const dialogs = useDialogs();
const [isDeleting, setIsDeleting] = React.useState(false);

const handleDelete = async () => {
const id = await dialogs.prompt('Enter the ID to delete', {
okText: 'Delete',
cancelText: 'Cancel',
});

if (id) {
const deleteConfirmed = await dialogs.confirm(
`Are you sure you want to delete "${id}"?`,
);
if (deleteConfirmed) {
try {
setIsDeleting(true);
await mockApiDelete(id);
dialogs.alert('Deleted!');
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
await dialogs.open(MyCustomDialog, { id, error: message });
} finally {
setIsDeleting(false);
}
}
}
};
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
<div style={{ display: 'flex', gap: 16 }}>
<LoadingButton
variant="contained"
loading={isDeleting}
onClick={handleDelete}
>
Delete
</LoadingButton>
</div>
</div>
);
}

export default function ToolpadDialogsNoSnap() {
return (
<DialogsProvider>
<DemoContent />
</DialogsProvider>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<DialogsProvider>
<DemoContent />
</DialogsProvider>
Loading

0 comments on commit 1719ed4

Please sign in to comment.