diff --git a/docs/pages/material-ui/react-table.js b/docs/pages/material-ui/react-table.js
index 398a5a9a46a551..9435cd782cfee7 100644
--- a/docs/pages/material-ui/react-table.js
+++ b/docs/pages/material-ui/react-table.js
@@ -4,7 +4,7 @@ import AppFrame from 'docs/src/modules/components/AppFrame';
import * as pageProps from 'docs/data/material/components/table/table.md?muiMarkdown';
export default function Page() {
- return ;
+ return ;
}
Page.getLayout = (page) => {
diff --git a/docs/src/modules/components/AppLayoutDocs.js b/docs/src/modules/components/AppLayoutDocs.js
index 29a79b06248c69..ec3e554a03837f 100644
--- a/docs/src/modules/components/AppLayoutDocs.js
+++ b/docs/src/modules/components/AppLayoutDocs.js
@@ -14,14 +14,12 @@ import {
import Head from 'docs/src/modules/components/Head';
import AppFrame from 'docs/src/modules/components/AppFrame';
import AppContainer from 'docs/src/modules/components/AppContainer';
-import AppTableOfContents from 'docs/src/modules/components/AppTableOfContents';
+import AppTableOfContents, { TOC_WIDTH } from 'docs/src/modules/components/AppTableOfContents';
import AppLayoutDocsFooter from 'docs/src/modules/components/AppLayoutDocsFooter';
import BackToTop from 'docs/src/modules/components/BackToTop';
import getProductInfoFromUrl from 'docs/src/modules/utils/getProductInfoFromUrl';
import { convertProductIdToName } from 'docs/src/modules/components/AppSearch';
-const TOC_WIDTH = 242;
-
const Main = styled('main', {
shouldForwardProp: (prop) => prop !== 'disableToc',
})(({ theme }) => ({
@@ -35,7 +33,7 @@ const Main = styled('main', {
{
props: ({ disableToc }) => disableToc,
style: {
- [theme.breakpoints.up('md')]: {
+ [theme.breakpoints.up('xl')]: {
marginRight: TOC_WIDTH / 2,
},
},
@@ -43,7 +41,7 @@ const Main = styled('main', {
{
props: ({ disableToc }) => !disableToc,
style: {
- [theme.breakpoints.up('md')]: {
+ [theme.breakpoints.up('xl')]: {
gridTemplateColumns: `1fr ${TOC_WIDTH}px`,
},
},
@@ -65,14 +63,14 @@ const StyledAppContainer = styled(AppContainer, {
},
variants: [
{
- props: ({ disableToc }) => disableToc,
+ props: ({ disableToc, container }) => disableToc && container === 'narrow',
style: {
// 105ch ≈ 930px
maxWidth: `calc(105ch + ${TOC_WIDTH / 2}px)`,
},
},
{
- props: ({ disableToc }) => !disableToc,
+ props: ({ disableToc, container }) => !disableToc && container === 'narrow',
style: {
// We're mostly hosting text content so max-width by px does not make sense considering font-size is system-adjustable.
fontFamily: 'Arial',
@@ -80,6 +78,15 @@ const StyledAppContainer = styled(AppContainer, {
maxWidth: '105ch',
},
},
+ {
+ props: ({ disableToc, container }) => !disableToc && container === 'wide',
+ style: {
+ maxWidth: theme.breakpoints.values.xl,
+ '& p, & li, & h1, & h2, & h3, & h4, & h5, & h6': {
+ maxWidth: '105ch',
+ },
+ },
+ },
{
props: ({ disableAd, hasTabs }) => !disableAd && hasTabs,
style: {
@@ -127,6 +134,7 @@ export default function AppLayoutDocs(props) {
// improves the UX. It's faster to transition, and you don't lose UI states, like scroll.
disableLayout = false,
disableToc = false,
+ container = 'narrow',
hasTabs = false,
location,
title,
@@ -166,7 +174,12 @@ export default function AppLayoutDocs(props) {
Render the TOCs first to avoid layout shift when the HTML is streamed.
See https://jakearchibald.com/2014/dont-use-flexbox-for-page-layout/ for more details.
*/}
-
+
{children}
@@ -185,6 +198,7 @@ AppLayoutDocs.propTypes = {
title: PropTypes.string,
}),
children: PropTypes.node.isRequired,
+ container: PropTypes.oneOf(['narrow', 'wide']),
description: PropTypes.string.isRequired,
disableAd: PropTypes.bool.isRequired,
disableLayout: PropTypes.bool,
diff --git a/docs/src/modules/components/AppTableOfContents.js b/docs/src/modules/components/AppTableOfContents.js
index 4ec860d0cb4395..5c97aefcec74d9 100644
--- a/docs/src/modules/components/AppTableOfContents.js
+++ b/docs/src/modules/components/AppTableOfContents.js
@@ -11,6 +11,16 @@ import { samePageLinkNavigation } from 'docs/src/modules/components/MarkdownLink
import TableOfContentsBanner from 'docs/src/components/banner/TableOfContentsBanner';
import featureToggle from 'docs/src/featureToggle';
import DiamondSponsors from 'docs/src/modules/components/DiamondSponsors';
+import FormatListBulletedIcon from '@mui/icons-material/FormatListBulleted';
+import ClickAwayListener from '@mui/material/ClickAwayListener';
+import Tooltip from '@mui/material/Tooltip';
+import Fab from '@mui/material/Fab';
+import Box from '@mui/material/Box';
+import Popper from '@mui/material/Popper';
+import Paper from '@mui/material/Paper';
+import Fade from '@mui/material/Fade';
+
+export const TOC_WIDTH = 242;
const Nav = styled('nav')(({ theme }) => ({
top: 'var(--MuiDocs-header-height)',
@@ -24,7 +34,7 @@ const Nav = styled('nav')(({ theme }) => ({
paddingRight: theme.spacing(4), // We can't use `padding` as @mui/stylis-plugin-rtl doesn't swap it
display: 'none',
scrollbarWidth: 'thin',
- [theme.breakpoints.up('md')]: {
+ [theme.breakpoints.up('xl')]: {
display: 'block',
},
}));
@@ -168,14 +178,124 @@ function shouldShowJobAd() {
const showJobAd = featureToggle.enable_job_banner && shouldShowJobAd();
+function TableOfContents({ toc, itemLink, onLinkClick }) {
+ const t = useTranslate();
+
+ return (
+
+
+ {showJobAd && (
+ ({
+ mb: 2,
+ p: 1,
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'flex-start',
+ backgroundColor: alpha(theme.palette.grey[50], 0.4),
+ border: '1px solid',
+ borderColor: (theme.vars || theme).palette.grey[200],
+ borderRadius: 1,
+ transitionProperty: 'all',
+ transitionTiming: 'cubic-bezier(0.4, 0, 0.2, 1)',
+ transitionDuration: '150ms',
+ '&:hover, &:focus-visible': {
+ borderColor: (theme.vars || theme).palette.primary[200],
+ },
+ }),
+ (theme) =>
+ theme.applyDarkStyles({
+ backgroundColor: alpha(theme.palette.primary[900], 0.2),
+ borderColor: (theme.vars || theme).palette.primaryDark[700],
+ '&:hover, &:focus-visible': {
+ borderColor: (theme.vars || theme).palette.primaryDark[500],
+ },
+ }),
+ ]}
+ >
+
+ {'🚀 Join the MUI team!'}
+
+
+ {/* eslint-disable-next-line material-ui/no-hardcoded-labels */}
+ {"We're looking for React Engineers and other amazing roles-come find out more!"}
+
+
+ )}
+
+ {toc.length > 0 ? (
+
+ {t('tableOfContents')}
+
+ {toc.map((item) => (
+
+ {itemLink(item, 1, onLinkClick)}
+ {item.children.length > 0 ? (
+
+ {item.children.map((subitem) => (
+
+ {itemLink(subitem, 2, onLinkClick)}
+ {subitem.children?.length > 0 ? (
+
+ {subitem.children.map((nestedSubItem) => (
+
+ {itemLink(nestedSubItem, 3, onLinkClick)}
+
+ ))}
+
+ ) : null}
+
+ ))}
+
+ ) : null}
+
+ ))}
+
+
+ ) : null}
+
+
+
+ );
+}
+
+TableOfContents.propTypes = {
+ itemLink: PropTypes.func.isRequired,
+ onLinkClick: PropTypes.func,
+ toc: PropTypes.array.isRequired,
+};
+
export default function AppTableOfContents(props) {
const { toc } = props;
const t = useTranslate();
const items = React.useMemo(() => flatten(toc), [toc]);
const [activeState, setActiveState] = React.useState(null);
+ const [popperAnchorEl, setPopperAnchorEl] = React.useState(null);
const clickedRef = React.useRef(false);
const unsetClickedRef = React.useRef(null);
+
+ const handlePopperOpen = (event) => {
+ setPopperAnchorEl(event.currentTarget);
+ };
+
+ const handlePopperClose = () => {
+ setPopperAnchorEl(null);
+ };
+
+ const popperOpen = Boolean(popperAnchorEl);
+
const findActiveIndex = React.useCallback(() => {
// Don't set the active index based on scroll if a link was just clicked
if (clickedRef.current) {
@@ -241,12 +361,35 @@ export default function AppTableOfContents(props) {
[],
);
- const itemLink = (item, level) => (
+ const itemLink = (item, level, onLinkClick) => (
{
+ handleClick(item.hash)(event);
+ if (onLinkClick) {
+ onLinkClick();
+ }
+ }}
+ active={activeState === item.hash}
+ level={level}
+ >
+
+
+ );
+
+ const mobileItemLink = (item, level, onLinkClick) => (
+ {
+ handleClick(item.hash)(event);
+ if (onLinkClick) {
+ onLinkClick();
+ }
+ }}
active={activeState === item.hash}
level={level}
>
@@ -255,89 +398,96 @@ export default function AppTableOfContents(props) {
);
return (
-
+
+
+
+
);
}
diff --git a/docs/src/modules/components/MarkdownDocs.js b/docs/src/modules/components/MarkdownDocs.js
index 8a1b1bffc1c5fc..5635e380ae7a87 100644
--- a/docs/src/modules/components/MarkdownDocs.js
+++ b/docs/src/modules/components/MarkdownDocs.js
@@ -10,6 +10,7 @@ export default function MarkdownDocs(props) {
const {
disableAd = false,
disableToc = false,
+ container,
demos = {},
docs,
demoComponents,
@@ -28,6 +29,7 @@ export default function MarkdownDocs(props) {
description={localizedDoc.description}
disableAd={disableAd}
disableToc={disableToc}
+ container={container}
location={localizedDoc.location}
title={localizedDoc.title}
toc={localizedDoc.toc}
@@ -53,6 +55,7 @@ export default function MarkdownDocs(props) {
}
MarkdownDocs.propTypes = {
+ container: PropTypes.oneOf(['narrow', 'wide']),
demoComponents: PropTypes.object,
demos: PropTypes.object,
disableAd: PropTypes.bool,
diff --git a/docs/src/modules/components/MarkdownDocsV2.js b/docs/src/modules/components/MarkdownDocsV2.js
index 87ae6c543b9d45..23abf739bea3e6 100644
--- a/docs/src/modules/components/MarkdownDocsV2.js
+++ b/docs/src/modules/components/MarkdownDocsV2.js
@@ -43,6 +43,7 @@ export default function MarkdownDocsV2(props) {
const {
disableAd = false,
disableToc = false,
+ container,
demos = {},
docs,
demoComponents,
@@ -220,6 +221,7 @@ export default function MarkdownDocsV2(props) {
description={localizedDoc.description}
disableAd={disableAd}
disableToc={disableToc}
+ container={container}
location={localizedDoc.location}
title={localizedDoc.title}
toc={activeToc}
@@ -274,6 +276,7 @@ export default function MarkdownDocsV2(props) {
MarkdownDocsV2.propTypes = {
componentsApiDescriptions: PropTypes.object,
componentsApiPageContents: PropTypes.object,
+ container: PropTypes.oneOf(['narrow', 'wide']),
demoComponents: PropTypes.object,
demos: PropTypes.object,
disableAd: PropTypes.bool,