From 002fa21370032bcaf1b28d29201e476f74412311 Mon Sep 17 00:00:00 2001 From: Olivier Tassinari Date: Sun, 25 Jun 2023 00:01:12 +0200 Subject: [PATCH] [docs-infra] Fix layout shift ad --- docs/src/modules/components/Ad.js | 7 +- docs/src/modules/components/AppLayoutDocs.js | 21 ++- .../AppLayoutDocsWithoutAppFrame.js | 166 ------------------ docs/src/modules/components/MarkdownDocs.js | 24 +-- docs/src/modules/components/MarkdownDocsV2.js | 31 ++-- docs/src/modules/components/ThemeContext.js | 15 +- docs/src/modules/components/ad.styles.js | 4 +- 7 files changed, 56 insertions(+), 212 deletions(-) delete mode 100644 docs/src/modules/components/AppLayoutDocsWithoutAppFrame.js diff --git a/docs/src/modules/components/Ad.js b/docs/src/modules/components/Ad.js index 53516d6cf3c125..aaaea2fe566be4 100644 --- a/docs/src/modules/components/Ad.js +++ b/docs/src/modules/components/Ad.js @@ -111,7 +111,7 @@ class AdErrorBoundary extends React.Component { } } -function Ad() { +export default function Ad() { const [adblock, setAdblock] = React.useState(null); const [carbonOut, setCarbonOut] = React.useState(null); @@ -218,7 +218,8 @@ function Ad() { sx={{ position: 'relative', display: 'block', - m: (theme) => theme.spacing(4, 0, 3), + mt: 4, + mb: 3, ...(adShape === 'image' && { minHeight: 126, }), @@ -241,5 +242,3 @@ function Ad() { ); } - -export default Ad; diff --git a/docs/src/modules/components/AppLayoutDocs.js b/docs/src/modules/components/AppLayoutDocs.js index 82f4ee53b6e5e8..69bcc1559349bb 100644 --- a/docs/src/modules/components/AppLayoutDocs.js +++ b/docs/src/modules/components/AppLayoutDocs.js @@ -47,15 +47,17 @@ const StyledAppContainer = styled(AppContainer, { ...(!disableAd && { ...(!hasTabs && { '&& .description': { - marginBottom: 198, + paddingBottom: 4 * 10 + 126, + marginBottom: 3 * 10, }, '&& .description.ad': { + paddingBottom: 0, marginBottom: 0, }, }), ...(hasTabs && { '&& .component-tabs .MuiTabs-root': { - marginBottom: 198, + marginBottom: 4 * 10 + 4 * 10 + 126, }, '&& .component-tabs.ad .MuiTabs-root': { marginBottom: 0, @@ -78,13 +80,16 @@ const ActionsDiv = styled('div')(({ theme }) => ({ }, })); -function AppLayoutDocs(props) { +export default function AppLayoutDocs(props) { const router = useRouter(); const { BannerComponent, children, description, disableAd = false, + // TODO, disableLayout should be the default, retaining the layout between pages + // improves the UX. It's faster to transition, and you don't lose UI states, like scroll. + disableLayout = false, disableToc = false, hasTabs = false, location, @@ -112,8 +117,11 @@ function AppLayoutDocs(props) { productName = 'Joy UI'; } + const Layout = disableLayout ? React.Fragment : AppFrame; + const layoutProps = disableLayout ? {} : { BannerComponent }; + return ( - + - + ); } @@ -155,6 +163,7 @@ AppLayoutDocs.propTypes = { children: PropTypes.node.isRequired, description: PropTypes.string.isRequired, disableAd: PropTypes.bool.isRequired, + disableLayout: PropTypes.bool, disableToc: PropTypes.bool.isRequired, hasTabs: PropTypes.bool, location: PropTypes.string.isRequired, @@ -165,5 +174,3 @@ AppLayoutDocs.propTypes = { if (process.env.NODE_ENV !== 'production') { AppLayoutDocs.propTypes = exactProp(AppLayoutDocs.propTypes); } - -export default AppLayoutDocs; diff --git a/docs/src/modules/components/AppLayoutDocsWithoutAppFrame.js b/docs/src/modules/components/AppLayoutDocsWithoutAppFrame.js deleted file mode 100644 index 95d45b99d3d66f..00000000000000 --- a/docs/src/modules/components/AppLayoutDocsWithoutAppFrame.js +++ /dev/null @@ -1,166 +0,0 @@ -import * as React from 'react'; -import PropTypes from 'prop-types'; -import { useRouter } from 'next/router'; -import { styled } from '@mui/material/styles'; -import { exactProp } from '@mui/utils'; -import GlobalStyles from '@mui/material/GlobalStyles'; -import NoSsr from '@mui/material/NoSsr'; -import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; -import Head from 'docs/src/modules/components/Head'; -import EditPage from 'docs/src/modules/components/EditPage'; -import AppContainer from 'docs/src/modules/components/AppContainer'; -import AppTableOfContents from 'docs/src/modules/components/AppTableOfContents'; -import AdManager from 'docs/src/modules/components/AdManager'; -import AppLayoutDocsFooter from 'docs/src/modules/components/AppLayoutDocsFooter'; -import BackToTop from 'docs/src/modules/components/BackToTop'; - -const Main = styled('main', { - shouldForwardProp: (prop) => prop !== 'disableToc', -})(({ disableToc, theme }) => ({ - display: 'grid', - width: '100%', - ...(disableToc - ? { - [theme.breakpoints.up('lg')]: { - marginRight: '5%', - }, - } - : { - [theme.breakpoints.up('md')]: { - gridTemplateColumns: '1fr 242px', - }, - }), - '& .markdown-body .comment-link': { - display: 'inline-block', - }, -})); - -const StyledAppContainer = styled(AppContainer, { - shouldForwardProp: (prop) => prop !== 'disableAd' && prop !== 'hasTabs', -})(({ disableAd, hasTabs, theme }) => { - return { - position: 'relative', - // By default, a grid item cannot be smaller than the size of its content. - // https://stackoverflow.com/questions/43311943/prevent-content-from-expanding-grid-items - minWidth: 0, - ...(!disableAd && { - ...(!hasTabs && { - '&& .description': { - marginBottom: 198, - }, - '&& .description.ad': { - marginBottom: 0, - }, - }), - ...(hasTabs && { - '&& .component-tabs .MuiTabs-root': { - marginBottom: 198, - }, - '&& .component-tabs.ad .MuiTabs-root': { - marginBottom: 0, - }, - }), - }), - [theme.breakpoints.up('lg')]: { - paddingLeft: '60px', - paddingRight: '60px', - }, - }; -}); - -const ActionsDiv = styled('div')(({ theme }) => ({ - display: 'flex', - marginTop: -10, - marginBottom: -15, - [theme.breakpoints.up('lg')]: { - justifyContent: 'flex-end', - }, -})); - -function AppLayoutDocsWithoutAppFrame(props) { - const router = useRouter(); - const { - children, - description, - disableAd = false, - disableToc = false, - hasTabs = false, - location, - title, - toc, - } = props; - - if (description === undefined) { - throw new Error('Missing description in the page'); - } - - const { canonicalAs } = pathnameToLanguage(router.asPath); - let productName = 'MUI'; - if (canonicalAs.startsWith('/material-ui/')) { - productName = 'Material UI'; - } else if (canonicalAs.startsWith('/base-ui/')) { - productName = 'Base UI'; - } else if (canonicalAs.startsWith('/x/')) { - productName = 'MUI X'; - } else if (canonicalAs.startsWith('/system/')) { - productName = 'MUI System'; - } else if (canonicalAs.startsWith('/toolpad/')) { - productName = 'MUI Toolpad'; - } else if (canonicalAs.startsWith('/joy-ui/')) { - productName = 'Joy UI'; - } - - return ( - - - - -
- {/* - 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} - - - - - {disableToc ? null : } -
-
- -
- ); -} - -AppLayoutDocsWithoutAppFrame.propTypes = { - children: PropTypes.node.isRequired, - description: PropTypes.string.isRequired, - disableAd: PropTypes.bool.isRequired, - disableToc: PropTypes.bool.isRequired, - hasTabs: PropTypes.bool, - location: PropTypes.string.isRequired, - title: PropTypes.string.isRequired, - toc: PropTypes.array.isRequired, -}; - -if (process.env.NODE_ENV !== 'production') { - AppLayoutDocsWithoutAppFrame.propTypes = exactProp(AppLayoutDocsWithoutAppFrame.propTypes); -} - -export default AppLayoutDocsWithoutAppFrame; diff --git a/docs/src/modules/components/MarkdownDocs.js b/docs/src/modules/components/MarkdownDocs.js index a9dc56a165337b..d2415aab54476d 100644 --- a/docs/src/modules/components/MarkdownDocs.js +++ b/docs/src/modules/components/MarkdownDocs.js @@ -4,7 +4,7 @@ import path from 'path'; import { useRouter } from 'next/router'; import { useTheme } from '@mui/system'; import { exactProp } from '@mui/utils'; -import { CssVarsProvider, useColorScheme } from '@mui/joy/styles'; +import { CssVarsProvider as JoyCssVarsProvider, useColorScheme } from '@mui/joy/styles'; import Demo from 'docs/src/modules/components/Demo'; import MarkdownElement from 'docs/src/modules/components/MarkdownElement'; import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; @@ -40,7 +40,7 @@ export default function MarkdownDocs(props) { disableAd = false, disableToc = false, /** - * Some Joy pages, e.g. Joy theme builder, should not be a nested CssVarsProvider to control its own state. + * Some pages, e.g. Joy theme builder, should not be a nested CssVarsProvider to control its own state. * This config will skip the CssVarsProvider at the root of the page. */ disableCssVarsProvider = false, @@ -57,7 +57,7 @@ export default function MarkdownDocs(props) { const { description, location, rendered, title, toc } = localizedDoc; const isJoy = canonicalAs.startsWith('/joy-ui/') && !disableCssVarsProvider; - const Provider = isJoy ? CssVarsProvider : React.Fragment; + const CssVarsProvider = isJoy ? JoyCssVarsProvider : React.Fragment; const Wrapper = isJoy ? BrandingProvider : React.Fragment; return ( @@ -69,14 +69,14 @@ export default function MarkdownDocs(props) { title={title} toc={toc} > - - {disableAd ? null : ( - - - - - - )} + {disableAd ? null : ( + + + + + + )} + {isJoy && } {rendered.map((renderedMarkdownOrDemo, index) => { if (typeof renderedMarkdownOrDemo === 'string') { @@ -154,7 +154,7 @@ export default function MarkdownDocs(props) { /> ); })} - + ); } diff --git a/docs/src/modules/components/MarkdownDocsV2.js b/docs/src/modules/components/MarkdownDocsV2.js index aebb48508db55a..dfb6beb4c6dc16 100644 --- a/docs/src/modules/components/MarkdownDocsV2.js +++ b/docs/src/modules/components/MarkdownDocsV2.js @@ -4,13 +4,13 @@ import { useRouter } from 'next/router'; import kebabCase from 'lodash/kebabCase'; import { useTheme } from '@mui/system'; import { exactProp } from '@mui/utils'; -import { CssVarsProvider, useColorScheme } from '@mui/joy/styles'; +import { CssVarsProvider as JoyCssVarsProvider, useColorScheme } from '@mui/joy/styles'; import ComponentsApiContent from 'docs/src/modules/components/ComponentsApiContent'; import HooksApiContent from 'docs/src/modules/components/HooksApiContent'; import { getTranslatedHeader as getComponentTranslatedHeader } from 'docs/src/modules/components/ApiPage'; import MarkdownElement from 'docs/src/modules/components/MarkdownElementV2'; import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; -import AppLayoutDocsWithoutAppFrame from 'docs/src/modules/components/AppLayoutDocsWithoutAppFrame'; +import AppLayoutDocs from 'docs/src/modules/components/AppLayoutDocs'; import { useTranslate, useUserLanguage } from 'docs/src/modules/utils/i18n'; import BrandingProvider from 'docs/src/BrandingProvider'; import Ad from 'docs/src/modules/components/Ad'; @@ -163,7 +163,7 @@ export default function MarkdownDocsV2(props) { }); const isJoy = canonicalAs.startsWith('/joy-ui/'); - const Provider = isJoy ? CssVarsProvider : React.Fragment; + const CssVarsProvider = isJoy ? JoyCssVarsProvider : React.Fragment; const Wrapper = isJoy ? BrandingProvider : React.Fragment; const wrapperProps = { @@ -211,12 +211,13 @@ export default function MarkdownDocsV2(props) { } return ( - @@ -225,15 +226,15 @@ export default function MarkdownDocsV2(props) { '--MuiDocs-header-height': `${AppFrameHeight + TabsHeight}px`, }} > - - {isJoy && } - {disableAd ? null : ( - - - - - - )} + {disableAd ? null : ( + + + + + + )} + + {isJoy && } {commonElements} {activeTab === '' && rendered @@ -268,9 +269,9 @@ export default function MarkdownDocsV2(props) { pagesContents={hooksApiPageContents} /> )} - + - + ); } diff --git a/docs/src/modules/components/ThemeContext.js b/docs/src/modules/components/ThemeContext.js index 605a8ff5c9d980..a30fdcc08d7702 100644 --- a/docs/src/modules/components/ThemeContext.js +++ b/docs/src/modules/components/ThemeContext.js @@ -1,6 +1,9 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { ThemeProvider as MuiThemeProvider, createTheme } from '@mui/material/styles'; +import { + ThemeProvider as MdThemeProvider, + createTheme as createMdTheme, +} from '@mui/material/styles'; import { deepmerge } from '@mui/utils'; import useMediaQuery from '@mui/material/useMediaQuery'; import { enUS, zhCN, ptBR } from '@mui/material/locale'; @@ -208,7 +211,7 @@ export function ThemeProvider(props) { const theme = React.useMemo(() => { const brandingDesignTokens = getDesignTokens(paletteMode); const nextPalette = deepmerge(brandingDesignTokens.palette, paletteColors); - let nextTheme = createTheme( + let nextTheme = createMdTheme( { direction, ...brandingDesignTokens, @@ -229,6 +232,7 @@ export function ThemeProvider(props) { components: { MuiCssBaseline: { defaultProps: { + // TODO: Material UI v6, makes this the default enableColorScheme: true, }, }, @@ -245,13 +249,14 @@ export function ThemeProvider(props) { React.useEffect(() => { // Expose the theme as a global variable so people can play with it. window.theme = theme; - window.createTheme = createTheme; + window.createTheme = createMdTheme; }, [theme]); + // TODO: remove MdThemeProvider, top level layout should render the default theme. return ( - + {children} - + ); } diff --git a/docs/src/modules/components/ad.styles.js b/docs/src/modules/components/ad.styles.js index 6a655746989c6b..4df81aba6e892d 100644 --- a/docs/src/modules/components/ad.styles.js +++ b/docs/src/modules/components/ad.styles.js @@ -6,9 +6,7 @@ const adBodyImageStyles = (theme) => ({ display: 'block', overflow: 'hidden', border: `1px solid ${alpha(theme.palette.action.active, 0.12)}`, - padding: `${theme.spacing(1.5)} ${theme.spacing(1.5)} ${theme.spacing( - 1.5, - )} calc(${theme.spacing(1.5)} + 130px)`, + padding: '12px 12px 12px calc(12px + 130px)', borderRadius: theme.shape.borderRadius, }, imgWrapper: {