diff --git a/docs/pages/_app.js b/docs/pages/_app.js index 621abcb5ba334b..0bba2632dacbc7 100644 --- a/docs/pages/_app.js +++ b/docs/pages/_app.js @@ -34,7 +34,7 @@ import DocsStyledEngineProvider from 'docs/src/modules/utils/StyledEngineProvide import createEmotionCache from 'docs/src/createEmotionCache'; import BackToTop from 'docs/src/modules/components/BackToTop'; import findActivePage from 'docs/src/modules/utils/findActivePage'; -import FEATURE_TOGGLE from 'docs/src/featureToggle'; +import useRouterExtra from 'docs/src/modules/utils/useRouterExtra'; // Client-side cache, shared for the whole session of the user in the browser. const clientSideEmotionCache = createEmotionCache(); @@ -173,7 +173,7 @@ Tip: you can access the documentation \`theme\` object directly in the console. function AppWrapper(props) { const { children, emotionCache, pageProps } = props; - const router = useRouter(); + const { asPathWithoutLang, product, ...router } = useRouterExtra(); React.useEffect(() => { loadDependencies(); @@ -186,18 +186,17 @@ function AppWrapper(props) { } }, []); - const asPathWithoutLang = router.asPath.replace(/^\/[a-zA-Z]{2}\//, '/'); let productPages = pages; - if (asPathWithoutLang.startsWith('/base')) { + if (product === 'base') { productPages = basePages; } - if (asPathWithoutLang.startsWith('/material-ui')) { + if (product === 'material-ui') { productPages = materialPages; } - if (asPathWithoutLang.startsWith('/joy-ui')) { + if (product === 'joy-ui') { productPages = joyPages; } - if (asPathWithoutLang.startsWith('/system') && FEATURE_TOGGLE.enable_system_scope) { + if (product === 'system') { productPages = systemPages; } diff --git a/docs/public/static/branding/product-advanced-dark.svg b/docs/public/static/branding/product-advanced-dark.svg index 83069a62b7830a..05687f16d60435 100644 --- a/docs/public/static/branding/product-advanced-dark.svg +++ b/docs/public/static/branding/product-advanced-dark.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/public/static/branding/product-advanced-light.svg b/docs/public/static/branding/product-advanced-light.svg index 601d8e3f478de0..73f83f9328268b 100644 --- a/docs/public/static/branding/product-advanced-light.svg +++ b/docs/public/static/branding/product-advanced-light.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/public/static/branding/product-core-dark.svg b/docs/public/static/branding/product-core-dark.svg index 503677288a3e4c..1a3498917f4a91 100644 --- a/docs/public/static/branding/product-core-dark.svg +++ b/docs/public/static/branding/product-core-dark.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/public/static/branding/product-core-light.svg b/docs/public/static/branding/product-core-light.svg index d8b46130fd7234..7315993c50b8bd 100644 --- a/docs/public/static/branding/product-core-light.svg +++ b/docs/public/static/branding/product-core-light.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/public/static/branding/product-designkits-dark.svg b/docs/public/static/branding/product-designkits-dark.svg index 29a6ccc0eda0a1..91c151b8223301 100644 --- a/docs/public/static/branding/product-designkits-dark.svg +++ b/docs/public/static/branding/product-designkits-dark.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/public/static/branding/product-designkits-light.svg b/docs/public/static/branding/product-designkits-light.svg index 0cacb97003481e..2dcda68d5e8e09 100644 --- a/docs/public/static/branding/product-designkits-light.svg +++ b/docs/public/static/branding/product-designkits-light.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/public/static/branding/product-templates-dark.svg b/docs/public/static/branding/product-templates-dark.svg index 50a5ea9d7e2c4f..d90b2bd3b4abbd 100644 --- a/docs/public/static/branding/product-templates-dark.svg +++ b/docs/public/static/branding/product-templates-dark.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/public/static/branding/product-templates-light.svg b/docs/public/static/branding/product-templates-light.svg index 30741968186fc8..6d16c8ed32b15e 100644 --- a/docs/public/static/branding/product-templates-light.svg +++ b/docs/public/static/branding/product-templates-light.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/src/components/header/HeaderNavBar.tsx b/docs/src/components/header/HeaderNavBar.tsx index b6e4856c6463b3..f18ec124562123 100644 --- a/docs/src/components/header/HeaderNavBar.tsx +++ b/docs/src/components/header/HeaderNavBar.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import { useRouter } from 'next/router'; import { styled, alpha } from '@mui/material/styles'; import Box from '@mui/material/Box'; import Popper from '@mui/material/Popper'; @@ -10,6 +9,7 @@ import IconImage from 'docs/src/components/icon/IconImage'; import ROUTES from 'docs/src/route'; import FEATURE_TOGGLE from 'docs/src/featureToggle'; import Link from 'docs/src/modules/components/Link'; +import MuiProductSelector from 'docs/src/modules/components/MuiProductSelector'; const Navigation = styled('nav')(({ theme }) => ({ '& ul': { @@ -67,7 +67,9 @@ const ProductSubMenu = React.forwardRef( py: 2, '&:hover, &:focus': { backgroundColor: (theme) => - theme.palette.mode === 'dark' ? 'primaryDark.700' : 'grey.50', + theme.palette.mode === 'dark' + ? alpha(theme.palette.primaryDark[700], 0.4) + : theme.palette.grey[50], outline: 'none', '@media (hover: none)': { backgroundColor: 'initial', @@ -114,12 +116,12 @@ function getNextIndex(eventKey: KeyboardEvent['key'], currentIndex: number, leng } export default function HeaderNavBar() { - const router = useRouter(); - const asPathWithoutLang = router.asPath.replace(/^\/[a-zA-Z]{2}\//, '/'); const [subMenuOpen, setSubMenuOpen] = React.useState(false); const [subMenuIndex, setSubMenuIndex] = React.useState(null); + const [docsMenuOpen, setDocsMenuOpen] = React.useState(false); const navRef = React.useRef(null); const productsMenuRef = React.useRef(null); + const docsMenuRef = React.useRef(null); React.useEffect(() => { if (typeof subMenuIndex === 'number') { document.getElementById(PRODUCT_IDS[subMenuIndex])?.focus(); @@ -219,25 +221,23 @@ export default function HeaderNavBar() { anchorEl={productsMenuRef.current} transition placement="bottom-start" - style={{ zIndex: 1200 }} + style={{ zIndex: 1200, pointerEvents: subMenuOpen ? 'visible' : 'none' }} > {({ TransitionProps }) => ( ({ minWidth: 498, overflow: 'hidden', - borderColor: (theme) => - theme.palette.mode === 'dark' ? 'primaryDark.700' : 'grey.200', - bgcolor: (theme) => + borderColor: theme.palette.mode === 'dark' ? 'primaryDark.700' : 'grey.200', + bgcolor: theme.palette.mode === 'dark' ? 'primaryDark.900' : 'background.paper', - boxShadow: (theme) => - `0px 4px 20px ${ - theme.palette.mode === 'dark' - ? alpha(theme.palette.background.paper, 0.72) - : 'rgba(170, 180, 190, 0.3)' - }`, + boxShadow: `0px 4px 20px ${ + theme.palette.mode === 'dark' + ? alpha(theme.palette.background.paper, 0.72) + : 'rgba(170, 180, 190, 0.3)' + }`, '& ul': { margin: 0, padding: 0, @@ -245,11 +245,10 @@ export default function HeaderNavBar() { }, '& li:not(:last-of-type)': { borderBottom: '1px solid', - borderColor: (theme) => - theme.palette.mode === 'dark' ? 'primaryDark.700' : 'grey.100', + borderColor: theme.palette.mode === 'dark' ? 'primaryDark.700' : 'grey.100', }, '& a': { textDecoration: 'none' }, - }} + })} >
  • @@ -274,7 +273,7 @@ export default function HeaderNavBar() { MUI X } - description="Advanced and powerful components for complex use-cases." + description="Advanced and powerful components for complex use cases." onKeyDown={handleKeyDown} />
  • @@ -307,15 +306,58 @@ export default function HeaderNavBar() { )} -
  • - setDocsMenuOpen(true)} + onFocus={() => setDocsMenuOpen(true)} + onMouseOut={() => setDocsMenuOpen(false)} + onBlur={() => setDocsMenuOpen(false)} + > + + + {({ TransitionProps }) => ( + + ({ + minWidth: 498, + overflow: 'hidden', + borderColor: theme.palette.mode === 'dark' ? 'primaryDark.700' : 'grey.200', + bgcolor: theme.palette.mode === 'dark' ? 'primaryDark.900' : 'background.paper', + boxShadow: `0px 4px 20px ${ + theme.palette.mode === 'dark' + ? alpha(theme.palette.background.paper, 0.72) + : 'rgba(170, 180, 190, 0.3)' + }`, + '& ul': { + margin: 0, + padding: 0, + listStyle: 'none', + }, + })} + > +
      + +
    +
    +
    + )} +
  • diff --git a/docs/src/components/header/HeaderNavDropdown.tsx b/docs/src/components/header/HeaderNavDropdown.tsx index 3484f8449ab84e..e77d72a61b5b7d 100644 --- a/docs/src/components/header/HeaderNavDropdown.tsx +++ b/docs/src/components/header/HeaderNavDropdown.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import { useRouter } from 'next/router'; import { styled } from '@mui/material/styles'; import Box from '@mui/material/Box'; import Collapse from '@mui/material/Collapse'; @@ -12,6 +11,11 @@ import Link from 'docs/src/modules/components/Link'; import ROUTES from 'docs/src/route'; import FEATURE_TOGGLE from 'docs/src/featureToggle'; +const shouldShowJoy = + process.env.NODE_ENV === 'development' || + process.env.PULL_REQUEST || + FEATURE_TOGGLE.enable_joy_scope; + const Anchor = styled('a')<{ component?: React.ElementType; noLinkStyle?: boolean }>( ({ theme }) => ({ ...theme.typography.body2, @@ -27,7 +31,7 @@ const Anchor = styled('a')<{ component?: React.ElementType; noLinkStyle?: boolea padding: theme.spacing(1), borderRadius: theme.spacing(1), transition: theme.transitions.create('background'), - '&:hover, &:focus': { + '&:hover, &:focus-visible': { backgroundColor: theme.palette.mode === 'dark' ? theme.palette.primaryDark[700] : theme.palette.grey[100], // Reset on touch devices, it doesn't add specificity @@ -67,11 +71,42 @@ const PRODUCTS = [ }, ]; +const DOCS = [ + { + name: 'Material UI', + description: "React components that implement Google's Material Design.", + href: ROUTES.materialDocs, + }, + ...(shouldShowJoy + ? [ + { + name: 'Joy UI', + description: 'React components for building your design system.', + href: ROUTES.joyDocs, + }, + ] + : []), + { + name: 'MUI Base', + description: 'Unstyled React components and low-level hooks.', + href: ROUTES.baseDocs, + }, + { + name: 'MUI System', + description: 'CSS utilities for rapidly laying out custom designs.', + href: ROUTES.systemDocs, + }, + { + name: 'MUI X', + description: 'Advanced and powerful components for complex use cases.', + href: ROUTES.advancedComponents, + }, +]; + export default function HeaderNavDropdown() { - const router = useRouter(); - const asPathWithoutLang = router.asPath.replace(/^\/[a-zA-Z]{2}\//, '/'); const [open, setOpen] = React.useState(false); const [productsOpen, setProductsOpen] = React.useState(true); + const [docsOpen, setDocsOpen] = React.useState(false); const hambugerRef = React.useRef(null); return ( @@ -177,16 +212,47 @@ export default function HeaderNavDropdown() { )}
  • setDocsOpen((bool) => !bool)} + sx={{ justifyContent: 'space-between' }} > Docs + + + + theme.palette.mode === 'dark' ? 'primaryDark.700' : 'grey.100', + pl: 1, + pb: 1, + ml: 1, + }} + > + {DOCS.map((item) => ( +
  • + +
    {item.name}
    + + {item.description} + +
    +
  • + ))} + +
  • diff --git a/docs/src/modules/brandingTheme.ts b/docs/src/modules/brandingTheme.ts index 467deb4f527544..5fe7bf6c0c6df8 100644 --- a/docs/src/modules/brandingTheme.ts +++ b/docs/src/modules/brandingTheme.ts @@ -402,9 +402,7 @@ export function getThemedComponents(theme: Theme): { components: Theme['componen MuiMenu: { styleOverrides: { paper: { - mt: 0.5, minWidth: 160, - elevation: 0, color: theme.palette.text.secondary, backgroundImage: 'none', backgroundColor: @@ -516,20 +514,32 @@ export function getThemedComponents(theme: Theme): { components: Theme['componen theme.palette.mode === 'dark' ? alpha(theme.palette.grey[100], 0.1) : theme.palette.grey[200], + '&:hover': { + color: + theme.palette.mode === 'dark' + ? theme.palette.grey[300] + : theme.palette.grey[900], + }, + }), + ...(variant === 'outlined' && + color === 'primary' && { + '&:hover': { + color: theme.palette.primary[500], + }, }), ...(variant === 'filled' && color === 'default' && { border: '1px solid transparent', - color: theme.palette.mode === 'dark' ? '#fff' : theme.palette.primary[800], + color: theme.palette.mode === 'dark' ? '#fff' : theme.palette.primary[700], backgroundColor: theme.palette.mode === 'dark' - ? theme.palette.primaryDark[500] - : theme.palette.primary[100], + ? alpha(theme.palette.primaryDark[500], 0.8) + : alpha(theme.palette.primary[100], 0.5), '&:hover': { backgroundColor: theme.palette.mode === 'dark' ? theme.palette.primaryDark[600] - : theme.palette.primary[200], + : theme.palette.primary[100], }, }), // for labelling product in the search diff --git a/docs/src/modules/components/AppNavDrawer.js b/docs/src/modules/components/AppNavDrawer.js index 3776d5f681ad75..3ec99f9d4a1f88 100644 --- a/docs/src/modules/components/AppNavDrawer.js +++ b/docs/src/modules/components/AppNavDrawer.js @@ -23,10 +23,8 @@ import { useUserLanguage, useTranslate } from 'docs/src/modules/utils/i18n'; import ArrowDropDownRoundedIcon from '@mui/icons-material/ArrowDropDownRounded'; import DoneRounded from '@mui/icons-material/DoneRounded'; import FEATURE_TOGGLE from 'docs/src/featureToggle'; -import IconImage from 'docs/src/components/icon/IconImage'; -import Link from 'docs/src/modules/components/Link'; -import ROUTES from 'docs/src/route'; import { isNewLocation } from 'docs/src/modules/utils/replaceUrl'; +import MuiProductSelector from 'docs/src/modules/components/MuiProductSelector'; import materialPkgJson from '../../../../packages/mui-material/package.json'; import joyPkgJson from '../../../../packages/mui-joy/package.json'; import basePkgJson from '../../../../packages/mui-base/package.json'; @@ -34,99 +32,6 @@ import systemPkgJson from '../../../../packages/mui-system/package.json'; const savedScrollTop = {}; -const LinksWrapper = styled('div')(({ theme }) => { - return { - paddingLeft: theme.spacing(5.5), - paddingTop: theme.spacing(1.5), - height: FEATURE_TOGGLE.enable_joy_scope ? 162 : 124, - '& > a': { - position: 'relative', - display: 'flex', - minHeight: 40, - flexDirection: 'column', - alignItems: 'initial', - padding: theme.spacing(0, 1), - paddingTop: theme.spacing(1), - borderRadius: theme.shape.borderRadius, - color: - theme.palette.mode === 'dark' ? theme.palette.primary[300] : theme.palette.primary[600], - transition: theme.transitions.create(), - '&:hover': { - paddingBottom: theme.spacing(3.5), - backgroundColor: - theme.palette.mode === 'dark' - ? alpha(theme.palette.primaryDark[700], 0.4) - : theme.palette.grey[50], - '& .MuiTypography-body2': { - opacity: 1, - transform: 'translateY(0px)', - }, - }, - '& .MuiTypography-body1': { - zIndex: 1, - }, - '& .MuiTypography-body2': { - opacity: 0, - position: 'absolute', - top: '28px', - transition: theme.transitions.create(), - }, - '& svg': { - width: 18, - height: 18, - }, - }, - }; -}); - -const ProductLabel = styled(Typography)(({ theme }) => ({ - marginBottom: theme.spacing(0.3), - fontSize: theme.typography.pxToRem(12), - fontWeight: theme.typography.fontWeightBold, - textTransform: 'uppercase', - letterSpacing: '.05rem', - color: theme.palette.mode === 'dark' ? theme.palette.primary[300] : theme.palette.primary[600], -})); - -function ProductSubMenu(props) { - return ( - - - theme.palette.mode === 'dark' - ? theme.palette.primaryDark[700] - : theme.palette.grey[100], - }, - }} - > - {props.icon} - -
    - - {props.name} - - - {props.description} - -
    -
    - ); -} - -ProductSubMenu.propTypes = { - description: PropTypes.string, - icon: PropTypes.element, - name: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), -}; - function ProductDrawerButton(props) { const [anchorEl, setAnchorEl] = React.useState(null); const open = Boolean(anchorEl); @@ -137,7 +42,6 @@ function ProductDrawerButton(props) { setAnchorEl(null); }; - /* eslint-disable material-ui/no-hardcoded-labels */ return (