From 32f79a11cfeffb6111a48fa997599b453cb3a75f Mon Sep 17 00:00:00 2001 From: Brijesh Bittu <717550+brijeshb42@users.noreply.github.com> Date: Tue, 3 Mar 2026 22:40:02 +0530 Subject: [PATCH 1/5] [code-infra] Migrate simpler modules from docs to mui-docs These come with minimal transitive dependencies and easier to migrate to on X --- docs/data/docs-infra/pages.ts | 2 +- docs/data/docs/pages.ts | 2 +- docs/data/joy/pages.ts | 2 +- docs/data/material/pages.ts | 2 +- docs/data/system/pages.ts | 2 +- docs/pages/_app.js | 14 +-- docs/pages/_document.js | 4 +- docs/pages/components.tsx | 4 +- docs/scripts/i18n.ts | 6 +- docs/src/BrandingCssVarsProvider.tsx | 2 +- docs/src/modules/components/AppFrame.tsx | 4 +- docs/src/modules/components/AppLayoutDocs.js | 2 +- .../modules/components/AppLayoutDocsFooter.js | 4 +- docs/src/modules/components/AppNavDrawer.tsx | 6 +- .../modules/components/AppNavDrawerItem.tsx | 2 +- docs/src/modules/components/AppSearch.d.ts | 2 +- docs/src/modules/components/AppSearch.js | 4 +- docs/src/modules/components/Demo.js | 6 +- docs/src/modules/components/DemoSandbox.js | 2 +- docs/src/modules/components/DemoToolbar.js | 6 +- .../src/modules/components/GoogleAnalytics.js | 4 +- docs/src/modules/components/Head.tsx | 2 +- docs/src/modules/components/MarkdownLinks.ts | 2 +- .../MaterialFreeTemplatesCollection.js | 2 +- .../modules/components/MuiProductSelector.tsx | 2 +- docs/src/modules/components/Notifications.tsx | 2 +- docs/src/modules/components/OpenMuiChat.tsx | 4 +- docs/src/modules/components/TemplateFrame.js | 2 +- docs/src/modules/components/TopLayoutBlog.js | 2 +- .../modules/components/TopLayoutCaseStudy.js | 2 +- docs/src/modules/sandbox/CodeSandbox.ts | 2 +- docs/src/modules/sandbox/CreateReactApp.ts | 2 +- docs/src/modules/sandbox/Dependencies.ts | 4 +- docs/src/modules/sandbox/MuiChat.ts | 2 +- docs/src/modules/sandbox/StackBlitz.ts | 2 +- docs/src/modules/sandbox/types.ts | 2 +- docs/src/modules/utils/codeStylingSolution.js | 4 +- .../modules/utils/getProductInfoFromUrl.ts | 2 +- .../modules/utils/mapApiPageTranslations.js | 47 +-------- .../modules/utils/stylingSolutionMapping.js | 2 +- packages/markdown/index.d.mts | 1 + packages/mui-docs/package.json | 12 ++- .../mui-docs/src/DemoContext}/DemoContext.tsx | 19 +++- packages/mui-docs/src/DemoContext/index.ts | 8 ++ .../mui-docs/src/MuiPage}/MuiPage.ts | 9 +- packages/mui-docs/src/MuiPage/index.ts | 1 + .../mui-docs/src/PageContext}/PageContext.tsx | 12 ++- packages/mui-docs/src/PageContext/index.ts | 2 + .../StyledEngineProvider.js | 4 +- .../src/StyledEngineProvider/index.ts | 1 + .../mui-docs/src/codeStyling/codeStyling.js | 96 +++++++++++++++++++ packages/mui-docs/src/codeStyling/index.ts | 6 ++ .../mui-docs/src/codeVariant}/codeVariant.js | 6 +- packages/mui-docs/src/codeVariant/index.ts | 6 ++ packages/mui-docs/src/constants/constants.js | 18 ++++ packages/mui-docs/src/constants/index.ts | 1 + .../createEmotionCache}/createEmotionCache.ts | 2 +- .../mui-docs/src/createEmotionCache/index.ts | 1 + .../findActivePage}/findActivePage.test.js | 0 .../src/findActivePage}/findActivePage.ts | 2 +- packages/mui-docs/src/findActivePage/index.ts | 1 + .../getProductInfoFromUrl.test.js | 0 .../getProductInfoFromUrl.ts | 84 ++++++++++++++++ .../src/getProductInfoFromUrl/index.ts | 2 + .../src/globalSelector/globalSelector.ts | 17 ++++ packages/mui-docs/src/globalSelector/index.ts | 1 + .../mui-docs/src/helpers}/helpers.test.js | 0 .../mui-docs/src/helpers}/helpers.ts | 13 ++- packages/mui-docs/src/helpers/index.ts | 2 + .../src/mapApiPageTranslations/index.ts | 1 + .../mapApiPageTranslations.ts | 60 ++++++++++++ packages/mui-docs/src/utils/index.ts | 2 + packages/mui-docs/tsconfig.build.json | 4 +- pnpm-lock.yaml | 50 ++++++++++ 74 files changed, 489 insertions(+), 126 deletions(-) rename {docs/src/modules/components => packages/mui-docs/src/DemoContext}/DemoContext.tsx (87%) create mode 100644 packages/mui-docs/src/DemoContext/index.ts rename {docs/src => packages/mui-docs/src/MuiPage}/MuiPage.ts (92%) create mode 100644 packages/mui-docs/src/MuiPage/index.ts rename {docs/src/modules/components => packages/mui-docs/src/PageContext}/PageContext.tsx (66%) create mode 100644 packages/mui-docs/src/PageContext/index.ts rename {docs/src/modules/utils => packages/mui-docs/src/StyledEngineProvider}/StyledEngineProvider.js (91%) create mode 100644 packages/mui-docs/src/StyledEngineProvider/index.ts create mode 100644 packages/mui-docs/src/codeStyling/codeStyling.js create mode 100644 packages/mui-docs/src/codeStyling/index.ts rename {docs/src/modules/utils => packages/mui-docs/src/codeVariant}/codeVariant.js (95%) create mode 100644 packages/mui-docs/src/codeVariant/index.ts create mode 100644 packages/mui-docs/src/constants/constants.js create mode 100644 packages/mui-docs/src/constants/index.ts rename {docs/src => packages/mui-docs/src/createEmotionCache}/createEmotionCache.ts (85%) create mode 100644 packages/mui-docs/src/createEmotionCache/index.ts rename {docs/src/modules/utils => packages/mui-docs/src/findActivePage}/findActivePage.test.js (100%) rename {docs/src/modules/utils => packages/mui-docs/src/findActivePage}/findActivePage.ts (96%) create mode 100644 packages/mui-docs/src/findActivePage/index.ts rename {docs/src/modules/utils => packages/mui-docs/src/getProductInfoFromUrl}/getProductInfoFromUrl.test.js (100%) create mode 100644 packages/mui-docs/src/getProductInfoFromUrl/getProductInfoFromUrl.ts create mode 100644 packages/mui-docs/src/getProductInfoFromUrl/index.ts create mode 100644 packages/mui-docs/src/globalSelector/globalSelector.ts create mode 100644 packages/mui-docs/src/globalSelector/index.ts rename {docs/src/modules/utils => packages/mui-docs/src/helpers}/helpers.test.js (100%) rename {docs/src/modules/utils => packages/mui-docs/src/helpers}/helpers.ts (90%) create mode 100644 packages/mui-docs/src/helpers/index.ts create mode 100644 packages/mui-docs/src/mapApiPageTranslations/index.ts create mode 100644 packages/mui-docs/src/mapApiPageTranslations/mapApiPageTranslations.ts create mode 100644 packages/mui-docs/src/utils/index.ts diff --git a/docs/data/docs-infra/pages.ts b/docs/data/docs-infra/pages.ts index de3c12f3ad00a3..903120f7b48ad2 100644 --- a/docs/data/docs-infra/pages.ts +++ b/docs/data/docs-infra/pages.ts @@ -1,4 +1,4 @@ -import type { MuiPage } from 'docs/src/MuiPage'; +import type { MuiPage } from '@mui/docs/MuiPage'; const pages: readonly MuiPage[] = [ { diff --git a/docs/data/docs/pages.ts b/docs/data/docs/pages.ts index 55b233c9a1b4ce..41ac7470552b9b 100644 --- a/docs/data/docs/pages.ts +++ b/docs/data/docs/pages.ts @@ -1,4 +1,4 @@ -import type { MuiPage } from 'docs/src/MuiPage'; +import type { MuiPage } from '@mui/docs/MuiPage'; import standardNavIcons from 'docs/src/modules/components/AppNavIcons'; const pages: readonly MuiPage[] = [ diff --git a/docs/data/joy/pages.ts b/docs/data/joy/pages.ts index d18ded364dd1a6..9aa9b998236e71 100644 --- a/docs/data/joy/pages.ts +++ b/docs/data/joy/pages.ts @@ -1,4 +1,4 @@ -import type { MuiPage } from 'docs/src/MuiPage'; +import type { MuiPage } from '@mui/docs/MuiPage'; import pagesApi from 'docs/data/joy/pagesApi'; const pages: readonly MuiPage[] = [ diff --git a/docs/data/material/pages.ts b/docs/data/material/pages.ts index 920fedc266820d..a1dd8bfdfd9aad 100644 --- a/docs/data/material/pages.ts +++ b/docs/data/material/pages.ts @@ -1,6 +1,6 @@ import standardNavIcons from 'docs/src/modules/components/AppNavIcons'; import pagesApi from 'docs/data/material/pagesApi'; -import { MuiPage } from 'docs/src/MuiPage'; +import { MuiPage } from '@mui/docs/MuiPage'; const pages: MuiPage[] = [ { diff --git a/docs/data/system/pages.ts b/docs/data/system/pages.ts index df9d99f86e4a4c..1b71b829e50962 100644 --- a/docs/data/system/pages.ts +++ b/docs/data/system/pages.ts @@ -1,4 +1,4 @@ -import type { MuiPage } from 'docs/src/MuiPage'; +import type { MuiPage } from '@mui/docs/MuiPage'; import pagesApi from 'docs/data/system/pagesApi'; const pages: readonly MuiPage[] = [ diff --git a/docs/pages/_app.js b/docs/pages/_app.js index f00d64293375e9..3ad4c55e00a2fc 100644 --- a/docs/pages/_app.js +++ b/docs/pages/_app.js @@ -14,18 +14,18 @@ import docsInfraPages from 'docs/data/docs-infra/pages'; import materialPages from 'docs/data/material/pages'; import joyPages from 'docs/data/joy/pages'; import systemPages from 'docs/data/system/pages'; -import PageContext from 'docs/src/modules/components/PageContext'; -import DemoContext from 'docs/src/modules/components/DemoContext'; +import PageContext from '@mui/docs/PageContext'; +import DemoContext from '@mui/docs/DemoContext'; import GoogleAnalytics from 'docs/src/modules/components/GoogleAnalytics'; import { CodeCopyProvider } from '@mui/docs/CodeCopy'; import { ThemeProvider } from '@mui/docs/ThemeContext'; -import { CodeVariantProvider } from 'docs/src/modules/utils/codeVariant'; +import { CodeVariantProvider } from '@mui/docs/codeVariant'; import GlobalStyles from '@mui/material/GlobalStyles'; import { extendTheme, useColorScheme as useJoyColorScheme } from '@mui/joy/styles'; -import DocsStyledEngineProvider from 'docs/src/modules/utils/StyledEngineProvider'; -import createEmotionCache from 'docs/src/createEmotionCache'; -import findActivePage from 'docs/src/modules/utils/findActivePage'; -import getProductInfoFromUrl from 'docs/src/modules/utils/getProductInfoFromUrl'; +import DocsStyledEngineProvider from '@mui/docs/StyledEngineProvider'; +import createEmotionCache from '@mui/docs/createEmotionCache'; +import findActivePage from '@mui/docs/findActivePage'; +import getProductInfoFromUrl from '@mui/docs/getProductInfoFromUrl'; import { AnalyticsProvider } from 'docs/src/modules/components/AnalyticsProvider'; import { DocsProvider } from '@mui/docs/DocsProvider'; import { mapTranslations } from '@mui/docs/i18n'; diff --git a/docs/pages/_document.js b/docs/pages/_document.js index f3c2d3b3a9025a..e1fbfd469a9eee 100644 --- a/docs/pages/_document.js +++ b/docs/pages/_document.js @@ -6,8 +6,8 @@ import Document, { Html, Head, Main, NextScript } from 'next/document'; import GlobalStyles from '@mui/material/GlobalStyles'; import MuiInitColorSchemeScript from '@mui/material/InitColorSchemeScript'; import JoyInitColorSchemeScript from '@mui/joy/InitColorSchemeScript'; -import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; -import createEmotionCache from 'docs/src/createEmotionCache'; +import { pathnameToLanguage } from '@mui/docs/helpers'; +import createEmotionCache from '@mui/docs/createEmotionCache'; import { getMetaThemeColor } from '@mui/docs/branding'; import { fontClasses } from './_app'; diff --git a/docs/pages/components.tsx b/docs/pages/components.tsx index 1cff498b7aef35..7560e95e4fe40d 100644 --- a/docs/pages/components.tsx +++ b/docs/pages/components.tsx @@ -10,10 +10,10 @@ import AppHeader from 'docs/src/layouts/AppHeader'; import AppFooter from 'docs/src/layouts/AppFooter'; import BrandingCssVarsProvider from 'docs/src/BrandingCssVarsProvider'; import Section from 'docs/src/layouts/Section'; -import { pageToTitleI18n } from 'docs/src/modules/utils/helpers'; +import { pageToTitleI18n } from '@mui/docs/helpers'; import { useTranslate } from '@mui/docs/i18n'; import { Link } from '@mui/docs/Link'; -import type { MuiPage } from 'docs/src/MuiPage'; +import type { MuiPage } from '@mui/docs/MuiPage'; import materialPages from 'docs/data/material/pages'; export default function Components() { diff --git a/docs/scripts/i18n.ts b/docs/scripts/i18n.ts index 3b21af909238f6..f1e726147317a1 100644 --- a/docs/scripts/i18n.ts +++ b/docs/scripts/i18n.ts @@ -1,11 +1,11 @@ // @ts-check import path from 'path'; import fs from 'node:fs/promises'; -import { pageToTitle } from 'docs/src/modules/utils/helpers'; +import { pageToTitle } from '@mui/docs/helpers'; import materialPages from 'docs/data/material/pages'; import systemPages from 'docs/data/system/pages'; import joyPages from 'docs/data/joy/pages'; -import { MuiPage } from 'docs/src/MuiPage'; +import { MuiPage } from '@mui/docs/MuiPage'; const EXCLUDES = ['/api', '/blog', '/x/react-', '/toolpad']; @@ -19,7 +19,7 @@ async function run() { output.pages = {}; /** - * @param {readonly import('docs/src/MuiPage').MuiPage[]} pages + * @param {readonly import('@mui/docs/MuiPage').MuiPage[]} pages */ const traverse = (pages: MuiPage[]) => { pages.forEach((page) => { diff --git a/docs/src/BrandingCssVarsProvider.tsx b/docs/src/BrandingCssVarsProvider.tsx index 334c87f12da180..76da1f8a2d4e15 100644 --- a/docs/src/BrandingCssVarsProvider.tsx +++ b/docs/src/BrandingCssVarsProvider.tsx @@ -5,7 +5,7 @@ import { ThemeProvider, createTheme, PaletteColorOptions } from '@mui/material/s import { unstable_useEnhancedEffect as useEnhancedEffect } from '@mui/material/utils'; import { colorChannel, getContrastRatio, lighten, darken } from '@mui/system/colorManipulator'; import CssBaseline from '@mui/material/CssBaseline'; -import { getCookie, pathnameToLanguage } from 'docs/src/modules/utils/helpers'; +import { getCookie, pathnameToLanguage } from '@mui/docs/helpers'; // @ts-ignore to bypass type checking in MUI X repo import { NextNProgressBar } from 'docs/src/modules/components/AppFrame'; import { getDesignTokens, getThemedComponents } from '@mui/docs/branding'; diff --git a/docs/src/modules/components/AppFrame.tsx b/docs/src/modules/components/AppFrame.tsx index ce4b9442f422f3..08602480f421eb 100644 --- a/docs/src/modules/components/AppFrame.tsx +++ b/docs/src/modules/components/AppFrame.tsx @@ -17,12 +17,12 @@ import SvgHamburgerMenu from 'docs/src/icons/SvgHamburgerMenu'; import AppNavDrawer from 'docs/src/modules/components/AppNavDrawer'; import AppSettingsDrawer from 'docs/src/modules/components/AppSettingsDrawer'; import Notifications from 'docs/src/modules/components/Notifications'; -import PageContext from 'docs/src/modules/components/PageContext'; +import PageContext from '@mui/docs/PageContext'; import { useTranslate } from '@mui/docs/i18n'; import LogoWithCopyMenu from 'docs/src/components/action/LogoWithCopyMenu'; import AppFrameBanner from 'docs/src/components/banner/AppFrameBanner'; import { DemoPageThemeProvider } from 'docs/src/theming'; -import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; +import { pathnameToLanguage } from '@mui/docs/helpers'; import SearchButton from './SearchButton'; const nProgressStart = debounce(() => { diff --git a/docs/src/modules/components/AppLayoutDocs.js b/docs/src/modules/components/AppLayoutDocs.js index 29a79b06248c69..6587612061fafa 100644 --- a/docs/src/modules/components/AppLayoutDocs.js +++ b/docs/src/modules/components/AppLayoutDocs.js @@ -17,7 +17,7 @@ import AppContainer from 'docs/src/modules/components/AppContainer'; import AppTableOfContents 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 getProductInfoFromUrl from '@mui/docs/getProductInfoFromUrl'; import { convertProductIdToName } from 'docs/src/modules/components/AppSearch'; const TOC_WIDTH = 242; diff --git a/docs/src/modules/components/AppLayoutDocsFooter.js b/docs/src/modules/components/AppLayoutDocsFooter.js index 8f2fe169c65780..1302b0338b0d9e 100644 --- a/docs/src/modules/components/AppLayoutDocsFooter.js +++ b/docs/src/modules/components/AppLayoutDocsFooter.js @@ -26,11 +26,11 @@ import YouTubeIcon from '@mui/icons-material/YouTube'; import RssFeedIcon from '@mui/icons-material/RssFeed'; // Other imports import { Link } from '@mui/docs/Link'; -import PageContext from 'docs/src/modules/components/PageContext'; +import PageContext from '@mui/docs/PageContext'; import SvgMuiLogotype from 'docs/src/icons/SvgMuiLogotype'; import EditPage from 'docs/src/modules/components/EditPage'; import { useUserLanguage, useTranslate } from '@mui/docs/i18n'; -import { pageToTitleI18n } from 'docs/src/modules/utils/helpers'; +import { pageToTitleI18n } from '@mui/docs/helpers'; import useLocalStorageState from '@mui/utils/useLocalStorageState'; const FooterLink = styled(Link)(({ theme }) => { diff --git a/docs/src/modules/components/AppNavDrawer.tsx b/docs/src/modules/components/AppNavDrawer.tsx index 23721232c30b29..9cf5df67b39d6d 100644 --- a/docs/src/modules/components/AppNavDrawer.tsx +++ b/docs/src/modules/components/AppNavDrawer.tsx @@ -20,11 +20,11 @@ import ArrowDropDownRoundedIcon from '@mui/icons-material/ArrowDropDownRounded'; import DoneRounded from '@mui/icons-material/DoneRounded'; import LogoWithCopyMenu from 'docs/src/components/action/LogoWithCopyMenu'; import AppNavDrawerItem from 'docs/src/modules/components/AppNavDrawerItem'; -import { pageToTitleI18n } from 'docs/src/modules/utils/helpers'; -import PageContext, { ProductVersion } from 'docs/src/modules/components/PageContext'; +import { pageToTitleI18n } from '@mui/docs/helpers'; +import PageContext, { ProductVersion } from '@mui/docs/PageContext'; import { useTranslate } from '@mui/docs/i18n'; import MuiProductSelector from 'docs/src/modules/components/MuiProductSelector'; -import { MuiPage } from 'docs/src/MuiPage'; +import { MuiPage } from '@mui/docs/MuiPage'; // TODO: Collapse should expose an API to customize the duration based on the height. function transitionTheme(theme: Theme) { diff --git a/docs/src/modules/components/AppNavDrawerItem.tsx b/docs/src/modules/components/AppNavDrawerItem.tsx index da9b756f152860..a341c1125a7dcd 100644 --- a/docs/src/modules/components/AppNavDrawerItem.tsx +++ b/docs/src/modules/components/AppNavDrawerItem.tsx @@ -7,7 +7,7 @@ import Box from '@mui/material/Box'; import Chip from '@mui/material/Chip'; import { samePageLinkNavigation } from 'docs/src/modules/components/MarkdownLinks'; import { Link, LinkProps } from '@mui/docs/Link'; -import { MuiPageIcon } from 'docs/src/MuiPage'; +import { MuiPageIcon } from '@mui/docs/MuiPage'; import standardNavIcons from './AppNavIcons'; interface ItemBaseProps { diff --git a/docs/src/modules/components/AppSearch.d.ts b/docs/src/modules/components/AppSearch.d.ts index 203b3aa8d74d61..c415f85f964b20 100644 --- a/docs/src/modules/components/AppSearch.d.ts +++ b/docs/src/modules/components/AppSearch.d.ts @@ -1,6 +1,6 @@ import * as React from 'react'; import { SxProps } from '@mui/material/styles'; -import { MuiPageContext } from './PageContext'; +import { MuiPageContext } from '@mui/docs/PageContext'; export function convertProductIdToName(productInfo: MuiPageContext): string | undefined; diff --git a/docs/src/modules/components/AppSearch.js b/docs/src/modules/components/AppSearch.js index 1499ab5998f9cf..c8da83455badda 100644 --- a/docs/src/modules/components/AppSearch.js +++ b/docs/src/modules/components/AppSearch.js @@ -19,12 +19,12 @@ import ChecklistRoundedIcon from '@mui/icons-material/ChecklistRounded'; import NewspaperRoundedIcon from '@mui/icons-material/NewspaperRounded'; import GlobalStyles from '@mui/material/GlobalStyles'; import { alpha } from '@mui/material/styles'; -import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; +import { pathnameToLanguage } from '@mui/docs/helpers'; import { LANGUAGES_SSR } from 'docs/config'; import { Link } from '@mui/docs/Link'; import { useTranslate, useUserLanguage } from '@mui/docs/i18n'; import useLazyCSS from '@mui/docs/useLazyCSS'; -import PageContext from 'docs/src/modules/components/PageContext'; +import PageContext from '@mui/docs/PageContext'; import SearchButton from './SearchButton'; function NewStartScreen() { diff --git a/docs/src/modules/components/Demo.js b/docs/src/modules/components/Demo.js index 3cdd7c49ac5268..93384c1897303f 100644 --- a/docs/src/modules/components/Demo.js +++ b/docs/src/modules/components/Demo.js @@ -18,9 +18,9 @@ import DemoSandbox from 'docs/src/modules/components/DemoSandbox'; import ReactRunner from 'docs/src/modules/components/ReactRunner'; import DemoEditor from 'docs/src/modules/components/DemoEditor'; import DemoEditorError from 'docs/src/modules/components/DemoEditorError'; -import { useDemoContext } from 'docs/src/modules/components/DemoContext'; -import { useCodeVariant } from 'docs/src/modules/utils/codeVariant'; -import { CODE_VARIANTS } from 'docs/src/modules/constants'; +import { useDemoContext } from '@mui/docs/DemoContext'; +import { useCodeVariant } from '@mui/docs/codeVariant'; +import { CODE_VARIANTS } from '@mui/docs/constants'; import { useUserLanguage, useTranslate } from '@mui/docs/i18n'; import stylingSolutionMapping from 'docs/src/modules/utils/stylingSolutionMapping'; import DemoToolbarRoot from 'docs/src/modules/components/DemoToolbarRoot'; diff --git a/docs/src/modules/components/DemoSandbox.js b/docs/src/modules/components/DemoSandbox.js index 58be1e8c2ffe30..33b327d2f4800d 100644 --- a/docs/src/modules/components/DemoSandbox.js +++ b/docs/src/modules/components/DemoSandbox.js @@ -14,7 +14,7 @@ import { useTranslate } from '@mui/docs/i18n'; import { unstable_useEnhancedEffect as useEnhancedEffect } from '@mui/utils'; import { DemoInstanceThemeProvider } from 'docs/src/theming'; import { ThemeOptionsContext } from '@mui/docs/ThemeContext'; -import { useDemoContext } from 'docs/src/modules/components/DemoContext'; +import { useDemoContext } from '@mui/docs/DemoContext'; const SRC_DOC = ` diff --git a/docs/src/modules/components/DemoToolbar.js b/docs/src/modules/components/DemoToolbar.js index 680b6275bab910..3153bfffb59c0c 100644 --- a/docs/src/modules/components/DemoToolbar.js +++ b/docs/src/modules/components/DemoToolbar.js @@ -18,12 +18,12 @@ import Divider from '@mui/material/Divider'; import RefreshRoundedIcon from '@mui/icons-material/RefreshRounded'; import ResetFocusIcon from '@mui/icons-material/CenterFocusWeak'; import { useRouter } from 'next/router'; -import { CODE_VARIANTS } from 'docs/src/modules/constants'; -import { useSetCodeVariant } from 'docs/src/modules/utils/codeVariant'; +import { CODE_VARIANTS } from '@mui/docs/constants'; +import { useSetCodeVariant } from '@mui/docs/codeVariant'; import { useTranslate } from '@mui/docs/i18n'; import OpenMuiChat from 'docs/src/modules/components/OpenMuiChat'; import stylingSolutionMapping from 'docs/src/modules/utils/stylingSolutionMapping'; -import { useDemoContext } from 'docs/src/modules/components/DemoContext'; +import { useDemoContext } from '@mui/docs/DemoContext'; import codeSandbox from '../sandbox/CodeSandbox'; import stackBlitz from '../sandbox/StackBlitz'; diff --git a/docs/src/modules/components/GoogleAnalytics.js b/docs/src/modules/components/GoogleAnalytics.js index c1538ccb2372c4..d3fcff7652608f 100644 --- a/docs/src/modules/components/GoogleAnalytics.js +++ b/docs/src/modules/components/GoogleAnalytics.js @@ -1,9 +1,9 @@ import * as React from 'react'; import useMediaQuery from '@mui/material/useMediaQuery'; import { useRouter } from 'next/router'; -import { useNoSsrCodeVariant } from 'docs/src/modules/utils/codeVariant'; +import { useNoSsrCodeVariant } from '@mui/docs/codeVariant'; import { useUserLanguage } from '@mui/docs/i18n'; -import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; +import { pathnameToLanguage } from '@mui/docs/helpers'; import { ThemeOptionsContext } from '@mui/docs/ThemeContext'; // So we can write code like: diff --git a/docs/src/modules/components/Head.tsx b/docs/src/modules/components/Head.tsx index 02598e9c80793c..7d8c9945580e32 100644 --- a/docs/src/modules/components/Head.tsx +++ b/docs/src/modules/components/Head.tsx @@ -3,7 +3,7 @@ import NextHead from 'next/head'; import { useRouter } from 'next/router'; import { LANGUAGES_SSR } from 'docs/config'; import { useUserLanguage, useTranslate } from '@mui/docs/i18n'; -import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; +import { pathnameToLanguage } from '@mui/docs/helpers'; // #host-reference const HOST = process.env.PULL_REQUEST_ID diff --git a/docs/src/modules/components/MarkdownLinks.ts b/docs/src/modules/components/MarkdownLinks.ts index 55db7b7fd56cab..e128d16475699a 100644 --- a/docs/src/modules/components/MarkdownLinks.ts +++ b/docs/src/modules/components/MarkdownLinks.ts @@ -1,6 +1,6 @@ import * as React from 'react'; import Router from 'next/router'; -import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; +import { pathnameToLanguage } from '@mui/docs/helpers'; export function samePageLinkNavigation(event: MouseEvent) { if ( diff --git a/docs/src/modules/components/MaterialFreeTemplatesCollection.js b/docs/src/modules/components/MaterialFreeTemplatesCollection.js index 43dcb5481f2bd7..43cd50464f3b89 100644 --- a/docs/src/modules/components/MaterialFreeTemplatesCollection.js +++ b/docs/src/modules/components/MaterialFreeTemplatesCollection.js @@ -11,7 +11,7 @@ import Visibility from '@mui/icons-material/Visibility'; import CodeRoundedIcon from '@mui/icons-material/CodeRounded'; import OpenInNewRoundedIcon from '@mui/icons-material/OpenInNewRounded'; import { useTranslate } from '@mui/docs/i18n'; -import { pascalCase } from 'docs/src/modules/utils/helpers'; +import { pascalCase } from '@mui/docs/helpers'; import sourceMaterialTemplates from 'docs/src/modules/material/sourceMaterialTemplates'; import codeSandbox from 'docs/src/modules/sandbox/CodeSandbox'; import stackBlitz from 'docs/src/modules/sandbox/StackBlitz'; diff --git a/docs/src/modules/components/MuiProductSelector.tsx b/docs/src/modules/components/MuiProductSelector.tsx index f3fffc1ee3f16d..d53d15681efb12 100644 --- a/docs/src/modules/components/MuiProductSelector.tsx +++ b/docs/src/modules/components/MuiProductSelector.tsx @@ -7,7 +7,7 @@ import Divider from '@mui/material/Divider'; import MenuList, { MenuListProps } from '@mui/material/MenuList'; import MenuItem, { MenuItemProps } from '@mui/material/MenuItem'; import ROUTES from 'docs/src/route'; -import PageContext from 'docs/src/modules/components/PageContext'; +import PageContext from '@mui/docs/PageContext'; import SvgMuiLogomark from 'docs/src/icons/SvgMuiLogomark'; import SvgBaseUiLogo from 'docs/src/icons/SvgBaseUiLogo'; import BackupTableRoundedIcon from '@mui/icons-material/BackupTableRounded'; diff --git a/docs/src/modules/components/Notifications.tsx b/docs/src/modules/components/Notifications.tsx index 9c8c88bb51a8e9..ec5f277bc98672 100644 --- a/docs/src/modules/components/Notifications.tsx +++ b/docs/src/modules/components/Notifications.tsx @@ -13,7 +13,7 @@ import { ClickAwayListener } from '@mui/base/ClickAwayListener'; import MuiList from '@mui/material/List'; import MuiListItem from '@mui/material/ListItem'; import MuiDivider from '@mui/material/Divider'; -import { getCookie } from 'docs/src/modules/utils/helpers'; +import { getCookie } from '@mui/docs/helpers'; import { useUserLanguage, useTranslate } from '@mui/docs/i18n'; async function fetchNotifications() { diff --git a/docs/src/modules/components/OpenMuiChat.tsx b/docs/src/modules/components/OpenMuiChat.tsx index e45df8d343f5f5..c54194428f8273 100644 --- a/docs/src/modules/components/OpenMuiChat.tsx +++ b/docs/src/modules/components/OpenMuiChat.tsx @@ -4,8 +4,8 @@ import Button, { ButtonProps } from '@mui/material/Button'; import CircularProgress from '@mui/material/CircularProgress'; import Snackbar from '@mui/material/Snackbar'; import Alert from '@mui/material/Alert'; -import PageContext from 'docs/src/modules/components/PageContext'; -import { useDemoContext } from 'docs/src/modules/components/DemoContext'; +import PageContext from '@mui/docs/PageContext'; +import { useDemoContext } from '@mui/docs/DemoContext'; import { createMuiChat } from '../sandbox/MuiChat'; import { DemoData } from '../sandbox/types'; diff --git a/docs/src/modules/components/TemplateFrame.js b/docs/src/modules/components/TemplateFrame.js index e80048af50e3f2..07e8bca3a4edbb 100644 --- a/docs/src/modules/components/TemplateFrame.js +++ b/docs/src/modules/components/TemplateFrame.js @@ -24,7 +24,7 @@ import PaletteIcon from '@mui/icons-material/PaletteOutlined'; import codeSandbox from 'docs/src/modules/sandbox/CodeSandbox'; import stackBlitz from 'docs/src/modules/sandbox/StackBlitz'; import sourceMaterialTemplates from 'docs/src/modules/material/sourceMaterialTemplates'; -import { pascalCase } from 'docs/src/modules/utils/helpers'; +import { pascalCase } from '@mui/docs/helpers'; const StyledAppBar = styled(AppBar)(({ theme }) => ({ position: 'relative', diff --git a/docs/src/modules/components/TopLayoutBlog.js b/docs/src/modules/components/TopLayoutBlog.js index 1baa63746a31d3..72f9a85418365a 100644 --- a/docs/src/modules/components/TopLayoutBlog.js +++ b/docs/src/modules/components/TopLayoutBlog.js @@ -15,7 +15,7 @@ import AppFooter from 'docs/src/layouts/AppFooter'; import HeroEnd from 'docs/src/components/home/HeroEnd'; import { MarkdownElement } from '@mui/docs/MarkdownElement'; import RichMarkdownElement from 'docs/src/modules/components/RichMarkdownElement'; -import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; +import { pathnameToLanguage } from '@mui/docs/helpers'; import ROUTES from 'docs/src/route'; import { Link } from '@mui/docs/Link'; diff --git a/docs/src/modules/components/TopLayoutCaseStudy.js b/docs/src/modules/components/TopLayoutCaseStudy.js index dceb3df9c2d974..5fb0f052d31d99 100644 --- a/docs/src/modules/components/TopLayoutCaseStudy.js +++ b/docs/src/modules/components/TopLayoutCaseStudy.js @@ -12,7 +12,7 @@ import AppContainer from 'docs/src/modules/components/AppContainer'; import AppFooter from 'docs/src/layouts/AppFooter'; import HeroEnd from 'docs/src/components/home/HeroEnd'; import RichMarkdownElement from 'docs/src/modules/components/RichMarkdownElement'; -import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; +import { pathnameToLanguage } from '@mui/docs/helpers'; import ROUTES from 'docs/src/route'; import { Link } from '@mui/docs/Link'; diff --git a/docs/src/modules/sandbox/CodeSandbox.ts b/docs/src/modules/sandbox/CodeSandbox.ts index 1aebe5d514a0c9..54559ce5da91bc 100644 --- a/docs/src/modules/sandbox/CodeSandbox.ts +++ b/docs/src/modules/sandbox/CodeSandbox.ts @@ -5,7 +5,7 @@ import SandboxDependencies from 'docs/src/modules/sandbox/Dependencies'; import * as CRA from 'docs/src/modules/sandbox/CreateReactApp'; import getFileExtension from 'docs/src/modules/sandbox/FileExtension'; import flattenRelativeImports from 'docs/src/modules/sandbox/FlattenRelativeImports'; -import type { SandboxConfig } from 'docs/src/modules/components/DemoContext'; +import type { SandboxConfig } from '@mui/docs/DemoContext'; import { DemoData, CodeVariant } from 'docs/src/modules/sandbox/types'; const CSB_DEV_DEPENDENCIES = { diff --git a/docs/src/modules/sandbox/CreateReactApp.ts b/docs/src/modules/sandbox/CreateReactApp.ts index 060d666ea302ea..76c509ed39d800 100644 --- a/docs/src/modules/sandbox/CreateReactApp.ts +++ b/docs/src/modules/sandbox/CreateReactApp.ts @@ -1,4 +1,4 @@ -import type { SandboxConfig } from 'docs/src/modules/components/DemoContext'; +import type { SandboxConfig } from '@mui/docs/DemoContext'; import { DemoData } from 'docs/src/modules/sandbox/types'; export const getHtml = ({ diff --git a/docs/src/modules/sandbox/Dependencies.ts b/docs/src/modules/sandbox/Dependencies.ts index 243b18044b9443..4cfe5efb8ae84f 100644 --- a/docs/src/modules/sandbox/Dependencies.ts +++ b/docs/src/modules/sandbox/Dependencies.ts @@ -1,5 +1,5 @@ -import { CODE_VARIANTS } from 'docs/src/modules/constants'; -import type { SandboxConfig } from 'docs/src/modules/components/DemoContext'; +import { CODE_VARIANTS } from '@mui/docs/constants'; +import type { SandboxConfig } from '@mui/docs/DemoContext'; import { DemoData } from './types'; const packagesWithBundledTypes = [ diff --git a/docs/src/modules/sandbox/MuiChat.ts b/docs/src/modules/sandbox/MuiChat.ts index 001842dbc955a6..255e69e1cb7364 100644 --- a/docs/src/modules/sandbox/MuiChat.ts +++ b/docs/src/modules/sandbox/MuiChat.ts @@ -1,5 +1,5 @@ /* eslint-disable import/prefer-default-export */ -import type { SandboxConfig } from 'docs/src/modules/components/DemoContext'; +import type { SandboxConfig } from '@mui/docs/DemoContext'; import { DemoData } from './types'; import SandboxDependencies from './Dependencies'; import flattenRelativeImports from './FlattenRelativeImports'; diff --git a/docs/src/modules/sandbox/StackBlitz.ts b/docs/src/modules/sandbox/StackBlitz.ts index 714984b2a3d4ee..6853ac7fc80c0d 100644 --- a/docs/src/modules/sandbox/StackBlitz.ts +++ b/docs/src/modules/sandbox/StackBlitz.ts @@ -1,7 +1,7 @@ import addHiddenInput from 'docs/src/modules/utils/addHiddenInput'; import SandboxDependencies from 'docs/src/modules/sandbox/Dependencies'; import flattenRelativeImports from 'docs/src/modules/sandbox/FlattenRelativeImports'; -import type { SandboxConfig } from 'docs/src/modules/components/DemoContext'; +import type { SandboxConfig } from '@mui/docs/DemoContext'; import { CodeVariant, DemoData } from 'docs/src/modules/sandbox/types'; import * as CRA from 'docs/src/modules/sandbox/CreateReactApp'; diff --git a/docs/src/modules/sandbox/types.ts b/docs/src/modules/sandbox/types.ts index d91b051d09bbd7..8126feacf28e2f 100644 --- a/docs/src/modules/sandbox/types.ts +++ b/docs/src/modules/sandbox/types.ts @@ -1,4 +1,4 @@ -import type { MuiProductId } from 'docs/src/modules/utils/getProductInfoFromUrl'; +import type { MuiProductId } from '@mui/docs/getProductInfoFromUrl'; export type CodeVariant = 'TS' | 'JS'; diff --git a/docs/src/modules/utils/codeStylingSolution.js b/docs/src/modules/utils/codeStylingSolution.js index a49890a92bf38e..d4337442525384 100644 --- a/docs/src/modules/utils/codeStylingSolution.js +++ b/docs/src/modules/utils/codeStylingSolution.js @@ -1,7 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { getCookie } from 'docs/src/modules/utils/helpers'; -import { CODE_STYLING } from 'docs/src/modules/constants'; +import { getCookie } from '@mui/docs/helpers'; +import { CODE_STYLING } from '@mui/docs/constants'; const CodeStylingContext = React.createContext({ codeStyling: CODE_STYLING.SYSTEM, diff --git a/docs/src/modules/utils/getProductInfoFromUrl.ts b/docs/src/modules/utils/getProductInfoFromUrl.ts index 5a44572596f514..068c41f9e7d1a1 100644 --- a/docs/src/modules/utils/getProductInfoFromUrl.ts +++ b/docs/src/modules/utils/getProductInfoFromUrl.ts @@ -1,4 +1,4 @@ -import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; +import { pathnameToLanguage } from '@mui/docs/helpers'; export type MuiProductId = | 'null' diff --git a/docs/src/modules/utils/mapApiPageTranslations.js b/docs/src/modules/utils/mapApiPageTranslations.js index 321b74a3d5f456..140196a368bb8e 100644 --- a/docs/src/modules/utils/mapApiPageTranslations.js +++ b/docs/src/modules/utils/mapApiPageTranslations.js @@ -1,48 +1,7 @@ -import { createRender } from '@mui/internal-markdown'; -import { LANGUAGES_IGNORE_PAGES } from '../../../config'; +import mapApiPageTranslationsBase from '@mui/docs/mapApiPageTranslations'; -const notEnglishJsonRegExp = /-([a-z]{2})\.json$/; +import { LANGUAGES_IGNORE_PAGES } from '../../../config'; export default function mapApiPageTranslations(req) { - const headingHashes = {}; - const translations = {}; - - // Process the English markdown before the other locales. - // English ToC anchor links are used in all languages - let filenames = []; - req.keys().forEach((filename) => { - if (filename.match(notEnglishJsonRegExp)) { - filenames.push(filename); - } else { - filenames = [filename].concat(filenames); - } - }); - - filenames.forEach((filename) => { - const matchNotEnglishMarkdown = filename.match(notEnglishJsonRegExp); - const userLanguage = matchNotEnglishMarkdown !== null ? matchNotEnglishMarkdown[1] : 'en'; - const translation = req(filename) || null; - - if (translation !== null && translation.componentDescription) { - const componentDescriptionToc = []; - const render = createRender({ - headingHashes, - toc: componentDescriptionToc, - userLanguage, - location: filenames, - options: { - ignoreLanguagePages: LANGUAGES_IGNORE_PAGES, - env: { - SOURCE_CODE_REPO: '', - }, - }, - }); - translation.componentDescription = render(translation.componentDescription); - translation.componentDescriptionToc = componentDescriptionToc; - } - - translations[userLanguage] = translation; - }); - - return translations; + return mapApiPageTranslationsBase(req, LANGUAGES_IGNORE_PAGES); } diff --git a/docs/src/modules/utils/stylingSolutionMapping.js b/docs/src/modules/utils/stylingSolutionMapping.js index 09648575583ac7..2c3e475d6ef755 100644 --- a/docs/src/modules/utils/stylingSolutionMapping.js +++ b/docs/src/modules/utils/stylingSolutionMapping.js @@ -1,4 +1,4 @@ -import { CODE_STYLING } from 'docs/src/modules/constants'; +import { CODE_STYLING } from '@mui/docs/constants'; const stylingSolutionMapping = { [CODE_STYLING.TAILWIND]: 'tailwind', diff --git a/packages/markdown/index.d.mts b/packages/markdown/index.d.mts index ed2364fe177416..305970d00a1cac 100644 --- a/packages/markdown/index.d.mts +++ b/packages/markdown/index.d.mts @@ -8,6 +8,7 @@ interface TableOfContentsEntry { export function createRender(context: { headingHashes?: Record; toc?: TableOfContentsEntry[]; + location?: string[]; userLanguage?: string; ignoreLanguagePages?: (path: string) => boolean; options: object; diff --git a/packages/mui-docs/package.json b/packages/mui-docs/package.json index 4e6e325eca5700..7c9da9cb36c1d8 100644 --- a/packages/mui-docs/package.json +++ b/packages/mui-docs/package.json @@ -10,6 +10,7 @@ "material design", "docs" ], + "type": "module", "repository": { "type": "git", "url": "git+https://github.com/mui/material-ui.git", @@ -21,7 +22,7 @@ }, "homepage": "https://github.com/mui/material-ui/tree/master/packages/mui-docs", "scripts": { - "build": "code-infra build --flat --copy \"src/translations/translations.json\" --copy \"src/nextFonts/fonts\"", + "build": "code-infra build --flat --bundle esm --copy \"src/translations/translations.json\" --copy \"src/nextFonts/fonts\"", "release": "pnpm build && pnpm publish", "test": "exit 0", "typescript": "tsc -p tsconfig.json" @@ -29,11 +30,13 @@ "dependencies": { "@babel/runtime": "^7.28.6", "@mui/internal-markdown": "workspace:^", + "@mui/stylis-plugin-rtl": "workspace:^", "clipboard-copy": "^4.0.1", "clsx": "^2.1.1", "fg-loadcss": "^3.1.0", "nprogress": "^0.2.0", - "prop-types": "^15.8.1" + "prop-types": "^15.8.1", + "stylis": "4.2.0" }, "devDependencies": { "@mui/icons-material": "workspace:*", @@ -48,12 +51,17 @@ "react": "19.2.4" }, "peerDependencies": { + "@emotion/cache": "^11.11.0", + "@emotion/react": "^11.11.4", + "@emotion/styled": "^11.11.0", "@mui/base": "^5.0.0 || ^5.0.0-beta || ^7.0.0 || ^7.0.0-beta", "@mui/icons-material": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta", "@mui/material": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta", + "@mui/material-nextjs": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta", "@mui/system": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta", "@mui/utils": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "@types/stylis": "^4.2.7", "chai": "^6.0.1", "csstype": "^3.1.3", "next": "^13.5.1 || ^14 || ^15.0.0", diff --git a/docs/src/modules/components/DemoContext.tsx b/packages/mui-docs/src/DemoContext/DemoContext.tsx similarity index 87% rename from docs/src/modules/components/DemoContext.tsx rename to packages/mui-docs/src/DemoContext/DemoContext.tsx index d03b112474d1a1..ed6a91a074da01 100644 --- a/docs/src/modules/components/DemoContext.tsx +++ b/packages/mui-docs/src/DemoContext/DemoContext.tsx @@ -1,5 +1,22 @@ import * as React from 'react'; -import type { CodeVariant } from 'docs/src/modules/sandbox/types'; +import type { MuiProductId } from '../getProductInfoFromUrl'; + +export type CodeVariant = 'TS' | 'JS'; + +type RelativeModule = { + module: string; + raw: string; +}; + +export interface DemoData { + title: string; + language: string; + raw: string; + codeVariant: CodeVariant; + githubLocation: string; + productId?: Exclude; + relativeModules?: RelativeModule[]; +} export interface SandboxConfig { /** diff --git a/packages/mui-docs/src/DemoContext/index.ts b/packages/mui-docs/src/DemoContext/index.ts new file mode 100644 index 00000000000000..853b1f8d94b324 --- /dev/null +++ b/packages/mui-docs/src/DemoContext/index.ts @@ -0,0 +1,8 @@ +export { default, useDemoContext } from './DemoContext'; +export type { + CodeVariant, + DemoData, + SandboxConfig, + IframeWrapperProps, + DemoContextValue, +} from './DemoContext'; diff --git a/docs/src/MuiPage.ts b/packages/mui-docs/src/MuiPage/MuiPage.ts similarity index 92% rename from docs/src/MuiPage.ts rename to packages/mui-docs/src/MuiPage/MuiPage.ts index 6cf953846e2ee5..487d11c131c048 100644 --- a/docs/src/MuiPage.ts +++ b/packages/mui-docs/src/MuiPage/MuiPage.ts @@ -1,7 +1,12 @@ import * as React from 'react'; -import standardNavIcons from './modules/components/AppNavIcons'; -export type MuiPageIcon = keyof typeof standardNavIcons | React.ComponentType; +export type MuiPageIcon = + | 'ReaderIcon' + | 'BookIcon' + | 'DescriptionIcon' + | 'VisibilityIcon' + | 'WebIcon' + | React.ComponentType; export interface MuiPage { pathname: string; diff --git a/packages/mui-docs/src/MuiPage/index.ts b/packages/mui-docs/src/MuiPage/index.ts new file mode 100644 index 00000000000000..192b5af4617568 --- /dev/null +++ b/packages/mui-docs/src/MuiPage/index.ts @@ -0,0 +1 @@ +export type { MuiPage, MuiPageIcon, OrderedMuiPage } from './MuiPage'; diff --git a/docs/src/modules/components/PageContext.tsx b/packages/mui-docs/src/PageContext/PageContext.tsx similarity index 66% rename from docs/src/modules/components/PageContext.tsx rename to packages/mui-docs/src/PageContext/PageContext.tsx index 953b98519ed4e7..6f9f2f7795107a 100644 --- a/docs/src/modules/components/PageContext.tsx +++ b/packages/mui-docs/src/PageContext/PageContext.tsx @@ -1,7 +1,13 @@ import * as React from 'react'; -import type { MuiPage } from 'docs/src/MuiPage'; -import type { MuiProductId } from 'docs/src/modules/utils/getProductInfoFromUrl'; -import { RootSvgProps } from 'docs/src/icons/RootSvg'; +import type { Theme } from '@mui/material/styles'; +import type { SxProps } from '@mui/system'; +import type { MuiPage } from '../MuiPage'; +import type { MuiProductId } from '../getProductInfoFromUrl'; + +export type RootSvgProps

= Omit, 'ref'> & { + sx?: SxProps; + ref?: React.Ref; +} & P; export interface ProductVersion { text: string; diff --git a/packages/mui-docs/src/PageContext/index.ts b/packages/mui-docs/src/PageContext/index.ts new file mode 100644 index 00000000000000..0f55c5c325a4a3 --- /dev/null +++ b/packages/mui-docs/src/PageContext/index.ts @@ -0,0 +1,2 @@ +export { default } from './PageContext'; +export type { RootSvgProps, ProductVersion, ProductInfo, MuiPageContext } from './PageContext'; diff --git a/docs/src/modules/utils/StyledEngineProvider.js b/packages/mui-docs/src/StyledEngineProvider/StyledEngineProvider.js similarity index 91% rename from docs/src/modules/utils/StyledEngineProvider.js rename to packages/mui-docs/src/StyledEngineProvider/StyledEngineProvider.js index 54f58a250c3161..928e7677639e0e 100644 --- a/docs/src/modules/utils/StyledEngineProvider.js +++ b/packages/mui-docs/src/StyledEngineProvider/StyledEngineProvider.js @@ -6,8 +6,8 @@ import { createEmotionCache as createCache } from '@mui/material-nextjs/v15-page import { prefixer } from 'stylis'; import rtlPlugin from '@mui/stylis-plugin-rtl'; import GlobalStyles from '@mui/material/GlobalStyles'; -import { ThemeOptionsContext } from '@mui/docs/ThemeContext'; -import globalSelector from './globalSelector'; +import { ThemeOptionsContext } from '../ThemeContext'; +import globalSelector from '../globalSelector'; // Cache for the rtl version of the styles const cacheRtl = createCache({ diff --git a/packages/mui-docs/src/StyledEngineProvider/index.ts b/packages/mui-docs/src/StyledEngineProvider/index.ts new file mode 100644 index 00000000000000..30cd6986a545fa --- /dev/null +++ b/packages/mui-docs/src/StyledEngineProvider/index.ts @@ -0,0 +1 @@ +export { default } from './StyledEngineProvider'; diff --git a/packages/mui-docs/src/codeStyling/codeStyling.js b/packages/mui-docs/src/codeStyling/codeStyling.js new file mode 100644 index 00000000000000..90c8150df99052 --- /dev/null +++ b/packages/mui-docs/src/codeStyling/codeStyling.js @@ -0,0 +1,96 @@ +import PropTypes from 'prop-types'; +import * as React from 'react'; +import { CODE_STYLING } from '../constants'; +import { getCookie } from '../helpers/index'; + +const CodeStylingContext = React.createContext({ + codeStyling: CODE_STYLING.SYSTEM, + setCodeStyling: () => {}, +}); +if (process.env.NODE_ENV !== 'production') { + CodeStylingContext.displayName = 'CodeStyling'; +} + +function useFirstRender() { + const firstRenderRef = React.useRef(true); + React.useEffect(() => { + firstRenderRef.current = false; + }, []); + + return firstRenderRef.current; +} + +export function CodeStylingProvider(props) { + const { children } = props; + + const [codeStyling, setCodeStyling] = React.useState(CODE_STYLING.SYSTEM); + + const navigatedCodeStyling = React.useMemo(() => { + const navigatedCodeMatch = + typeof window !== 'undefined' ? window.location.hash.match(/\.(js|tsx)$/) : null; + + if (navigatedCodeMatch === null) { + return undefined; + } + + if (typeof window !== 'undefined') { + if (window.location.hash.includes('tailwind-')) { + return CODE_STYLING.TAILWIND; + } + if (window.location.hash.includes('css-')) { + return CODE_STYLING.CSS; + } + if (window.location.hash.includes('system-')) { + return CODE_STYLING.SYSTEM; + } + } + + return undefined; + }, []); + + const persistedCodeStyling = React.useMemo(() => { + if (typeof window === 'undefined') { + return undefined; + } + return getCookie('codeStyling'); + }, []); + const isFirstRender = useFirstRender(); + + // We initialize from navigation or cookies. on subsequent renders the store is the truth + const noSsrCodeStyling = + isFirstRender === true + ? navigatedCodeStyling || persistedCodeStyling || codeStyling + : codeStyling; + + React.useEffect(() => { + if (codeStyling !== noSsrCodeStyling) { + setCodeStyling(noSsrCodeStyling); + } + }, [codeStyling, noSsrCodeStyling]); + + React.useEffect(() => { + document.cookie = `codeStyling=${codeStyling};path=/;max-age=31536000`; + }, [codeStyling]); + + const contextValue = React.useMemo(() => { + return { codeStyling, noSsrCodeStyling, setCodeStyling }; + }, [codeStyling, noSsrCodeStyling]); + + return {children}; +} + +CodeStylingProvider.propTypes = { + children: PropTypes.node.isRequired, +}; + +export function useCodeStyling() { + return React.useContext(CodeStylingContext).codeStyling; +} + +export function useNoSsrCodeStyling() { + return React.useContext(CodeStylingContext).noSsrCodeStyling; +} + +export function useSetCodeStyling() { + return React.useContext(CodeStylingContext).setCodeStyling; +} diff --git a/packages/mui-docs/src/codeStyling/index.ts b/packages/mui-docs/src/codeStyling/index.ts new file mode 100644 index 00000000000000..10b64755cb8762 --- /dev/null +++ b/packages/mui-docs/src/codeStyling/index.ts @@ -0,0 +1,6 @@ +export { + CodeStylingProvider, + useCodeStyling, + useNoSsrCodeStyling, + useSetCodeStyling, +} from './codeStyling'; diff --git a/docs/src/modules/utils/codeVariant.js b/packages/mui-docs/src/codeVariant/codeVariant.js similarity index 95% rename from docs/src/modules/utils/codeVariant.js rename to packages/mui-docs/src/codeVariant/codeVariant.js index a8b205745f116e..45738dfe85935c 100644 --- a/docs/src/modules/utils/codeVariant.js +++ b/packages/mui-docs/src/codeVariant/codeVariant.js @@ -1,7 +1,7 @@ -import * as React from 'react'; import PropTypes from 'prop-types'; -import { getCookie } from 'docs/src/modules/utils/helpers'; -import { CODE_VARIANTS } from 'docs/src/modules/constants'; +import * as React from 'react'; +import { CODE_VARIANTS } from '../constants'; +import { getCookie } from '../helpers/index'; const CodeVariantContext = React.createContext({ codeVariant: CODE_VARIANTS.TS, diff --git a/packages/mui-docs/src/codeVariant/index.ts b/packages/mui-docs/src/codeVariant/index.ts new file mode 100644 index 00000000000000..af737046398e3e --- /dev/null +++ b/packages/mui-docs/src/codeVariant/index.ts @@ -0,0 +1,6 @@ +export { + CodeVariantProvider, + useCodeVariant, + useNoSsrCodeVariant, + useSetCodeVariant, +} from './codeVariant'; diff --git a/packages/mui-docs/src/constants/constants.js b/packages/mui-docs/src/constants/constants.js new file mode 100644 index 00000000000000..d8af43d95fcbae --- /dev/null +++ b/packages/mui-docs/src/constants/constants.js @@ -0,0 +1,18 @@ +export const CODE_VARIANTS = { + JS: 'JS', + TS: 'TS', +}; + +export const CODE_STYLING = { + SYSTEM: 'MUI System', + TAILWIND: 'Tailwind', + CSS: 'CSS', +}; + +// Valid languages to use in production +export const LANGUAGES_LABEL = [ + { + code: 'en', + text: 'English', + }, +]; diff --git a/packages/mui-docs/src/constants/index.ts b/packages/mui-docs/src/constants/index.ts new file mode 100644 index 00000000000000..3f1d403c89823a --- /dev/null +++ b/packages/mui-docs/src/constants/index.ts @@ -0,0 +1 @@ +export { CODE_VARIANTS, CODE_STYLING, LANGUAGES_LABEL } from './constants'; diff --git a/docs/src/createEmotionCache.ts b/packages/mui-docs/src/createEmotionCache/createEmotionCache.ts similarity index 85% rename from docs/src/createEmotionCache.ts rename to packages/mui-docs/src/createEmotionCache/createEmotionCache.ts index b5f726c09ef8ac..40d25eee5d56e7 100644 --- a/docs/src/createEmotionCache.ts +++ b/packages/mui-docs/src/createEmotionCache/createEmotionCache.ts @@ -1,6 +1,6 @@ import { createEmotionCache as createCache } from '@mui/material-nextjs/v15-pagesRouter'; import { prefixer } from 'stylis'; -import globalSelector from './modules/utils/globalSelector'; +import globalSelector from '../globalSelector'; export default function createEmotionCache() { // TODO remove prepend: true once JSS is out diff --git a/packages/mui-docs/src/createEmotionCache/index.ts b/packages/mui-docs/src/createEmotionCache/index.ts new file mode 100644 index 00000000000000..d9a95a95904bc5 --- /dev/null +++ b/packages/mui-docs/src/createEmotionCache/index.ts @@ -0,0 +1 @@ +export { default } from './createEmotionCache'; diff --git a/docs/src/modules/utils/findActivePage.test.js b/packages/mui-docs/src/findActivePage/findActivePage.test.js similarity index 100% rename from docs/src/modules/utils/findActivePage.test.js rename to packages/mui-docs/src/findActivePage/findActivePage.test.js diff --git a/docs/src/modules/utils/findActivePage.ts b/packages/mui-docs/src/findActivePage/findActivePage.ts similarity index 96% rename from docs/src/modules/utils/findActivePage.ts rename to packages/mui-docs/src/findActivePage/findActivePage.ts index 331ff3ee5954b0..6d5a7800a5d7cb 100644 --- a/docs/src/modules/utils/findActivePage.ts +++ b/packages/mui-docs/src/findActivePage/findActivePage.ts @@ -1,4 +1,4 @@ -import type { MuiPage } from 'docs/src/MuiPage'; +import type { MuiPage } from '../MuiPage'; export default function findActivePage( currentPages: MuiPage[], diff --git a/packages/mui-docs/src/findActivePage/index.ts b/packages/mui-docs/src/findActivePage/index.ts new file mode 100644 index 00000000000000..83fa6a8ae8550d --- /dev/null +++ b/packages/mui-docs/src/findActivePage/index.ts @@ -0,0 +1 @@ +export { default } from './findActivePage'; diff --git a/docs/src/modules/utils/getProductInfoFromUrl.test.js b/packages/mui-docs/src/getProductInfoFromUrl/getProductInfoFromUrl.test.js similarity index 100% rename from docs/src/modules/utils/getProductInfoFromUrl.test.js rename to packages/mui-docs/src/getProductInfoFromUrl/getProductInfoFromUrl.test.js diff --git a/packages/mui-docs/src/getProductInfoFromUrl/getProductInfoFromUrl.ts b/packages/mui-docs/src/getProductInfoFromUrl/getProductInfoFromUrl.ts new file mode 100644 index 00000000000000..682d42f6af7596 --- /dev/null +++ b/packages/mui-docs/src/getProductInfoFromUrl/getProductInfoFromUrl.ts @@ -0,0 +1,84 @@ +import { pathnameToLanguage } from '../helpers/helpers'; + +export type MuiProductId = + | 'null' + | 'base-ui' + | 'material-ui' + | 'joy-ui' + | 'system' + | 'docs-infra' + | 'docs' + | 'x-data-grid' + | 'x-date-pickers' + | 'x-charts' + | 'x-tree-view' + | 'toolpad-studio' + | 'toolpad-core'; + +type MuiProductCategoryId = 'null' | 'core' | 'x'; + +interface MuiProductInfo { + productId: MuiProductId; + productCategoryId: MuiProductCategoryId; +} + +// This is a fallback logic to define the productId and productCategoryId of the page. +// Markdown pages can override this value when the URL patterns they follow are a bit strange, +// which should stay the rare exception. +export default function getProductInfoFromUrl(asPath: string): MuiProductInfo { + const asPathWithoutLang = pathnameToLanguage(asPath).canonicalAsServer; + const firstFolder = asPathWithoutLang.replace(/^\/+([^/]+)\/.*/, '$1'); + + // When serialized undefined/null are the same, so we encode null as 'null' to be + // able to differentiate when the value isn't set vs. set to the right null value. + let productCategoryId = 'null'; + let productId = 'null'; + + if ( + firstFolder === 'material-ui' || + firstFolder === 'joy-ui' || + firstFolder === 'base-ui' || + firstFolder === 'system' + ) { + productCategoryId = 'core'; + productId = firstFolder; + } + + if (firstFolder === 'x') { + productCategoryId = 'x'; + productId = `x-${asPathWithoutLang.replace('/x/react-', '').replace(/\/.*/, '')}`; + + // No match, give up on it. + if (productId === 'x-') { + productId = 'null'; + } + } + + if (firstFolder === 'toolpad') { + productCategoryId = 'toolpad'; + const secondFolder = asPathWithoutLang.replace(/^\/+[^/]+\/([^/]+)\/.*/, '$1'); + if (secondFolder === 'studio') { + productId = 'toolpad-studio'; + } else { + productId = 'toolpad-core'; + } + } + + if (firstFolder === 'docs') { + productId = firstFolder; + } + + // TODO remove, legacy + if (firstFolder === 'versions' || firstFolder === 'production-error') { + productId = 'docs'; + } + + if (asPathWithoutLang.startsWith('/experiments/docs/')) { + productId = 'docs-infra'; + } + + return { + productCategoryId, + productId, + } as MuiProductInfo; +} diff --git a/packages/mui-docs/src/getProductInfoFromUrl/index.ts b/packages/mui-docs/src/getProductInfoFromUrl/index.ts new file mode 100644 index 00000000000000..00851b346f833a --- /dev/null +++ b/packages/mui-docs/src/getProductInfoFromUrl/index.ts @@ -0,0 +1,2 @@ +export { default } from './getProductInfoFromUrl'; +export type { MuiProductId } from './getProductInfoFromUrl'; diff --git a/packages/mui-docs/src/globalSelector/globalSelector.ts b/packages/mui-docs/src/globalSelector/globalSelector.ts new file mode 100644 index 00000000000000..9c5a5325335dee --- /dev/null +++ b/packages/mui-docs/src/globalSelector/globalSelector.ts @@ -0,0 +1,17 @@ +/* eslint-disable default-case */ +import { Element, RULESET } from 'stylis'; + +// A workaround to https://github.com/emotion-js/emotion/issues/2836 +// to be able to use `:where` selector for styling. +export default function globalSelector(element: Element) { + switch (element.type) { + case RULESET: + element.props = (element.props as string[]).map((value: any) => { + if (value.match(/(:where|:is)\(/)) { + value = value.replace(/\.[^:]+(:where|:is)/, '$1'); + return value; + } + return value; + }); + } +} diff --git a/packages/mui-docs/src/globalSelector/index.ts b/packages/mui-docs/src/globalSelector/index.ts new file mode 100644 index 00000000000000..2778b8f5ee99c1 --- /dev/null +++ b/packages/mui-docs/src/globalSelector/index.ts @@ -0,0 +1 @@ +export { default } from './globalSelector'; diff --git a/docs/src/modules/utils/helpers.test.js b/packages/mui-docs/src/helpers/helpers.test.js similarity index 100% rename from docs/src/modules/utils/helpers.test.js rename to packages/mui-docs/src/helpers/helpers.test.js diff --git a/docs/src/modules/utils/helpers.ts b/packages/mui-docs/src/helpers/helpers.ts similarity index 90% rename from docs/src/modules/utils/helpers.ts rename to packages/mui-docs/src/helpers/helpers.ts index 5093dfe94f4580..63021926eaaa7c 100644 --- a/docs/src/modules/utils/helpers.ts +++ b/packages/mui-docs/src/helpers/helpers.ts @@ -1,6 +1,5 @@ import { camelCase, upperFirst } from 'es-toolkit/string'; -import { LANGUAGES } from 'docs/config'; -import { Translate } from '@mui/docs/i18n'; +import type { Translate } from '../i18n'; export function pascalCase(str: string) { return upperFirst(camelCase(str)); @@ -75,8 +74,14 @@ export function getCookie(name: string): string | undefined { * as is a reference to Next.js's as, the path in the URL * pathname is a reference to Next.js's pathname, the name of page in the filesystem * https://nextjs.org/docs/api-reference/next/router + * + * @param pathname - The URL pathname + * @param languages - List of supported language codes. Defaults to `['en']`. */ -export function pathnameToLanguage(pathname: string): { +export function pathnameToLanguage( + pathname: string, + languages: string[] = ['en'], +): { userLanguage: string; canonicalAs: string; canonicalAsServer: string; @@ -86,7 +91,7 @@ export function pathnameToLanguage(pathname: string): { const userLanguageCandidate = pathname.substring(1, 3); if ( - [...LANGUAGES, 'zh'].includes(userLanguageCandidate) && + [...languages, 'zh'].includes(userLanguageCandidate) && pathname.startsWith(`/${userLanguageCandidate}/`) ) { userLanguage = userLanguageCandidate; diff --git a/packages/mui-docs/src/helpers/index.ts b/packages/mui-docs/src/helpers/index.ts new file mode 100644 index 00000000000000..da6ac4dc5d0f22 --- /dev/null +++ b/packages/mui-docs/src/helpers/index.ts @@ -0,0 +1,2 @@ +export { pascalCase, pageToTitle, pageToTitleI18n, getCookie, pathnameToLanguage } from './helpers'; +export type { Page } from './helpers'; diff --git a/packages/mui-docs/src/mapApiPageTranslations/index.ts b/packages/mui-docs/src/mapApiPageTranslations/index.ts new file mode 100644 index 00000000000000..8e31cf9672576a --- /dev/null +++ b/packages/mui-docs/src/mapApiPageTranslations/index.ts @@ -0,0 +1 @@ +export { default } from './mapApiPageTranslations'; diff --git a/packages/mui-docs/src/mapApiPageTranslations/mapApiPageTranslations.ts b/packages/mui-docs/src/mapApiPageTranslations/mapApiPageTranslations.ts new file mode 100644 index 00000000000000..6b77bf2133371c --- /dev/null +++ b/packages/mui-docs/src/mapApiPageTranslations/mapApiPageTranslations.ts @@ -0,0 +1,60 @@ +import { createRender } from '@mui/internal-markdown'; + +const notEnglishJsonRegExp = /-([a-z]{2})\.json$/; + +interface Req { + keys(): string[]; + (filename: string): any; +} + +/** + * @param req - A webpack `require.context` for the API translation JSON files. + * @param languagesIgnorePages - A function that returns true if the page should not be translated. + * Typically `LANGUAGES_IGNORE_PAGES` from the docs config. + */ +export default function mapApiPageTranslations( + req: Req, + languagesIgnorePages?: (pathname: string) => boolean, +) { + const headingHashes: Record = {}; + const translations: Record = {}; + + // Process the English markdown before the other locales. + // English ToC anchor links are used in all languages + let filenames: string[] = []; + req.keys().forEach((filename: string) => { + if (filename.match(notEnglishJsonRegExp)) { + filenames.push(filename); + } else { + filenames = [filename].concat(filenames); + } + }); + + filenames.forEach((filename: string) => { + const matchNotEnglishMarkdown = filename.match(notEnglishJsonRegExp); + const userLanguage = matchNotEnglishMarkdown !== null ? matchNotEnglishMarkdown[1] : 'en'; + const translation = req(filename) || null; + + if (translation !== null && translation.componentDescription) { + const componentDescriptionToc: any[] = []; + const render = createRender({ + headingHashes, + toc: componentDescriptionToc, + userLanguage, + location: filenames, + options: { + ignoreLanguagePages: languagesIgnorePages || (() => false), + env: { + SOURCE_CODE_REPO: '', + }, + }, + }); + translation.componentDescription = render(translation.componentDescription); + translation.componentDescriptionToc = componentDescriptionToc; + } + + translations[userLanguage] = translation; + }); + + return translations; +} diff --git a/packages/mui-docs/src/utils/index.ts b/packages/mui-docs/src/utils/index.ts new file mode 100644 index 00000000000000..75f25aa95e3341 --- /dev/null +++ b/packages/mui-docs/src/utils/index.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line import/prefer-default-export +export { default as loadScript } from './loadScript'; diff --git a/packages/mui-docs/tsconfig.build.json b/packages/mui-docs/tsconfig.build.json index 25d95383a9f857..66f47dd6c42ef3 100644 --- a/packages/mui-docs/tsconfig.build.json +++ b/packages/mui-docs/tsconfig.build.json @@ -15,7 +15,9 @@ "exclude": ["src/**/*.spec.ts*", "src/**/*.test.ts*"], "references": [ { "path": "../mui-material/tsconfig.build.json" }, + { "path": "../mui-material-nextjs/tsconfig.build.json" }, { "path": "../mui-system/tsconfig.build.json" }, - { "path": "../mui-icons-material/tsconfig.build.json" } + { "path": "../mui-icons-material/tsconfig.build.json" }, + { "path": "../mui-stylis-plugin-rtl/tsconfig.build.json" } ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ceae7c4cbd0d59..d6371efc67ed7a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -844,18 +844,36 @@ importers: '@babel/runtime': specifier: ^7.28.6 version: 7.28.6 + '@emotion/cache': + specifier: ^11.11.0 + version: 11.14.0 + '@emotion/react': + specifier: ^11.11.4 + version: 11.14.0(@types/react@19.2.14)(react@19.2.4) + '@emotion/styled': + specifier: ^11.11.0 + version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) '@mui/base': specifier: ^5.0.0 || ^5.0.0-beta || ^7.0.0 || ^7.0.0-beta version: 5.0.0-beta.70(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@mui/internal-markdown': specifier: workspace:^ version: link:../markdown + '@mui/material-nextjs': + specifier: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta + version: 7.3.8(@emotion/cache@11.14.0)(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/server@11.11.0(@emotion/css@11.13.4))(@types/react@19.2.14)(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.8.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) + '@mui/stylis-plugin-rtl': + specifier: workspace:^ + version: link:../mui-stylis-plugin-rtl/build '@mui/system': specifier: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta version: 6.4.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) '@mui/utils': specifier: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta version: 7.3.6(@types/react@19.2.14)(react@19.2.4) + '@types/stylis': + specifier: ^4.2.7 + version: 4.2.7 chai: specifier: ^6.0.1 version: 6.2.2 @@ -877,6 +895,9 @@ importers: prop-types: specifier: ^15.8.1 version: 15.8.1 + stylis: + specifier: 4.2.0 + version: 4.2.0 devDependencies: '@mui/icons-material': specifier: workspace:* @@ -3745,6 +3766,24 @@ packages: '@types/react': optional: true + '@mui/material-nextjs@7.3.8': + resolution: {integrity: sha512-ewSnzgTiVGD+m0DQe4VxIkgpeKrb8a9745GXtfMtpoEz6Qhx96vDyz4k18BMx7zC7CWkGrEvVZcRVJaOyuIcXg==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@emotion/cache': ^11.11.0 + '@emotion/react': ^11.11.4 + '@emotion/server': ^11.11.0 + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + next: ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/cache': + optional: true + '@emotion/server': + optional: true + '@types/react': + optional: true + '@mui/material@5.15.4': resolution: {integrity: sha512-T/LGRAC+M0c+D3+y67eHwIN5bSje0TxbcJCWR0esNvU11T0QwrX3jedXItPNBwMupF2F5VWCDHBVLlFnN3+ABA==} engines: {node: '>=12.0.0'} @@ -15018,6 +15057,17 @@ snapshots: '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) '@types/react': 19.2.14 + '@mui/material-nextjs@7.3.8(@emotion/cache@11.14.0)(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/server@11.11.0(@emotion/css@11.13.4))(@types/react@19.2.14)(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.8.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4) + next: 15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.8.0)(@playwright/test@1.58.2)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@emotion/cache': 11.14.0 + '@emotion/server': 11.11.0(@emotion/css@11.13.4) + '@types/react': 19.2.14 + '@mui/material@5.15.4(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@babel/runtime': 7.28.6 From 2d027c25f9c98d9e3cac90bfeebafc81b6876540 Mon Sep 17 00:00:00 2001 From: Brijesh Bittu <717550+brijeshb42@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:03:14 +0530 Subject: [PATCH 2/5] Create pnpm catalog for docs/mui-docs --- docs/next.config.ts | 18 ++++++++--------- docs/package.json | 10 +++++----- packages/mui-docs/package.json | 10 +++++----- pnpm-lock.yaml | 36 +++++++++++++++++++++++++--------- pnpm-workspace.yaml | 8 ++++++++ 5 files changed, 54 insertions(+), 28 deletions(-) diff --git a/docs/next.config.ts b/docs/next.config.ts index 06f6f082de9a50..34731e41a4ab9d 100644 --- a/docs/next.config.ts +++ b/docs/next.config.ts @@ -259,15 +259,6 @@ export default withDocsInfra({ return map; }, - redirects: async () => { - return [ - { - source: '/base-ui/', - destination: 'https://base-ui.com', - permanent: true, - }, - ]; - }, // Used to signal we run pnpm build ...(process.env.NODE_ENV === 'production' ? { @@ -283,5 +274,14 @@ export default withDocsInfra({ { source: `/static/x/:rest*`, destination: 'http://0.0.0.0:3001/static/x/:rest*' }, ]; }, + redirects: async () => { + return [ + { + source: '/base-ui/', + destination: 'https://base-ui.com', + permanent: true, + }, + ]; + }, }), } satisfies NextConfig); diff --git a/docs/package.json b/docs/package.json index 25a526921cca77..ede88ef337ce21 100644 --- a/docs/package.json +++ b/docs/package.json @@ -21,10 +21,10 @@ "@babel/runtime": "^7.28.6", "@base-ui/react": "^1.2.0", "@docsearch/react": "^3.9.0", - "@emotion/cache": "^11.14.0", - "@emotion/react": "^11.14.0", - "@emotion/server": "^11.11.0", - "@emotion/styled": "^11.14.1", + "@emotion/cache": "catalog:docs", + "@emotion/react": "catalog:docs", + "@emotion/server": "catalog:docs", + "@emotion/styled": "catalog:docs", "@fortawesome/fontawesome-svg-core": "^6.7.2", "@fortawesome/free-solid-svg-icons": "^6.7.2", "@fortawesome/react-fontawesome": "^0.2.6", @@ -99,7 +99,7 @@ "react-window": "^2.2.7", "rimraf": "^6.1.3", "styled-components": "^6.3.11", - "stylis": "4.2.0", + "stylis": "catalog:docs", "use-count-up": "^3.0.1", "webpack-bundle-analyzer": "^5.2.0" }, diff --git a/packages/mui-docs/package.json b/packages/mui-docs/package.json index 7c9da9cb36c1d8..55a1e71e87836a 100644 --- a/packages/mui-docs/package.json +++ b/packages/mui-docs/package.json @@ -36,7 +36,7 @@ "fg-loadcss": "^3.1.0", "nprogress": "^0.2.0", "prop-types": "^15.8.1", - "stylis": "4.2.0" + "stylis": "catalog:docs" }, "devDependencies": { "@mui/icons-material": "workspace:*", @@ -51,9 +51,9 @@ "react": "19.2.4" }, "peerDependencies": { - "@emotion/cache": "^11.11.0", - "@emotion/react": "^11.11.4", - "@emotion/styled": "^11.11.0", + "@emotion/cache": "catalog:docs", + "@emotion/react": "catalog:docs", + "@emotion/styled": "catalog:docs", "@mui/base": "^5.0.0 || ^5.0.0-beta || ^7.0.0 || ^7.0.0-beta", "@mui/icons-material": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta", "@mui/material": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta", @@ -64,7 +64,7 @@ "@types/stylis": "^4.2.7", "chai": "^6.0.1", "csstype": "^3.1.3", - "next": "^13.5.1 || ^14 || ^15.0.0", + "next": "^13.5.1 || ^14 || ^15.0.0 || ^16.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d6371efc67ed7a..480c72ff1453d8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,24 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +catalogs: + docs: + '@emotion/cache': + specifier: ^11.14.0 + version: 11.14.0 + '@emotion/react': + specifier: ^11.14.0 + version: 11.14.0 + '@emotion/server': + specifier: ^11.11.0 + version: 11.11.0 + '@emotion/styled': + specifier: ^11.14.1 + version: 11.14.1 + stylis: + specifier: 4.2.0 + version: 4.2.0 + overrides: '@babel/core': 7.29.0 '@babel/plugin-transform-runtime': ^7.29.0 @@ -263,16 +281,16 @@ importers: specifier: ^3.9.0 version: 3.9.0(@algolia/client-search@5.18.0)(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(search-insights@2.13.0) '@emotion/cache': - specifier: ^11.14.0 + specifier: catalog:docs version: 11.14.0 '@emotion/react': - specifier: ^11.14.0 + specifier: catalog:docs version: 11.14.0(@types/react@19.2.14)(react@19.2.4) '@emotion/server': - specifier: ^11.11.0 + specifier: catalog:docs version: 11.11.0(@emotion/css@11.13.4) '@emotion/styled': - specifier: ^11.14.1 + specifier: catalog:docs version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) '@fortawesome/fontawesome-svg-core': specifier: ^6.7.2 @@ -497,7 +515,7 @@ importers: specifier: ^6.3.11 version: 6.3.11(patch_hash=383c648dfdb5dfc82fbe414d54027d8c982a01c6320370f0ecfdb387e753c09f)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) stylis: - specifier: 4.2.0 + specifier: catalog:docs version: 4.2.0 use-count-up: specifier: ^3.0.1 @@ -845,13 +863,13 @@ importers: specifier: ^7.28.6 version: 7.28.6 '@emotion/cache': - specifier: ^11.11.0 + specifier: catalog:docs version: 11.14.0 '@emotion/react': - specifier: ^11.11.4 + specifier: catalog:docs version: 11.14.0(@types/react@19.2.14)(react@19.2.4) '@emotion/styled': - specifier: ^11.11.0 + specifier: catalog:docs version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4) '@mui/base': specifier: ^5.0.0 || ^5.0.0-beta || ^7.0.0 || ^7.0.0-beta @@ -896,7 +914,7 @@ importers: specifier: ^15.8.1 version: 15.8.1 stylis: - specifier: 4.2.0 + specifier: catalog:docs version: 4.2.0 devDependencies: '@mui/icons-material': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 391bc056bf6bc7..4f2c81df19a83d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -13,3 +13,11 @@ onlyBuiltDependencies: - '@vvago/vale' engineStrict: true + +catalogs: + docs: + stylis: '4.2.0' + '@emotion/cache': '^11.14.0' + '@emotion/react': '^11.14.0' + '@emotion/server': '^11.11.0' + '@emotion/styled': '^11.14.1' From f55394af376b0e31f6c069747f42b55a8fc3af31 Mon Sep 17 00:00:00 2001 From: Brijesh Bittu <717550+brijeshb42@users.noreply.github.com> Date: Wed, 4 Mar 2026 14:02:32 +0530 Subject: [PATCH 3/5] Move GoogleAnalytics and AnalyticsProvider to @mui/docs - GoogleAnalytics: already clean (all imports use @mui/docs or @mui/material) - AnalyticsProvider: removed BrandingCssThemeProvider wrapper (cookie dialog inherits the branding theme from the parent ThemeProvider) - Updated docs/_app.js to import from @mui/docs --- docs/pages/_app.js | 53 +++++++++---------- docs/pages/_document.js | 2 +- .../AnalyticsProvider}/AnalyticsProvider.tsx | 29 +++++++--- .../mui-docs/src/AnalyticsProvider/index.ts | 1 + .../src/GoogleAnalytics/GoogleAnalytics.tsx | 27 ++++++---- .../mui-docs/src/GoogleAnalytics/index.ts | 1 + 6 files changed, 69 insertions(+), 44 deletions(-) rename {docs/src/modules/components => packages/mui-docs/src/AnalyticsProvider}/AnalyticsProvider.tsx (91%) create mode 100644 packages/mui-docs/src/AnalyticsProvider/index.ts rename docs/src/modules/components/GoogleAnalytics.js => packages/mui-docs/src/GoogleAnalytics/GoogleAnalytics.tsx (84%) create mode 100644 packages/mui-docs/src/GoogleAnalytics/index.ts diff --git a/docs/pages/_app.js b/docs/pages/_app.js index 3ad4c55e00a2fc..fe9b5a2bb1131c 100644 --- a/docs/pages/_app.js +++ b/docs/pages/_app.js @@ -1,43 +1,42 @@ import 'docs/src/modules/components/bootstrap'; // --- Post bootstrap ----- -import * as React from 'react'; -import { loadCSS } from 'fg-loadcss'; -import NextHead from 'next/head'; -import PropTypes from 'prop-types'; -import { useRouter } from 'next/router'; -import { LicenseInfo } from '@mui/x-license'; -import materialPkgJson from '@mui/material/package.json'; -import joyPkgJson from '@mui/joy/package.json'; -import systemPkgJson from '@mui/system/package.json'; -import generalDocsPages from 'docs/data/docs/pages'; -import docsInfraPages from 'docs/data/docs-infra/pages'; -import materialPages from 'docs/data/material/pages'; -import joyPages from 'docs/data/joy/pages'; -import systemPages from 'docs/data/system/pages'; -import PageContext from '@mui/docs/PageContext'; -import DemoContext from '@mui/docs/DemoContext'; -import GoogleAnalytics from 'docs/src/modules/components/GoogleAnalytics'; +import { AnalyticsProvider } from '@mui/docs/AnalyticsProvider'; import { CodeCopyProvider } from '@mui/docs/CodeCopy'; +import DemoContext from '@mui/docs/DemoContext'; +import { DocsProvider } from '@mui/docs/DocsProvider'; +import GoogleAnalytics from '@mui/docs/GoogleAnalytics'; +import PageContext from '@mui/docs/PageContext'; +import DocsStyledEngineProvider from '@mui/docs/StyledEngineProvider'; import { ThemeProvider } from '@mui/docs/ThemeContext'; import { CodeVariantProvider } from '@mui/docs/codeVariant'; -import GlobalStyles from '@mui/material/GlobalStyles'; -import { extendTheme, useColorScheme as useJoyColorScheme } from '@mui/joy/styles'; -import DocsStyledEngineProvider from '@mui/docs/StyledEngineProvider'; import createEmotionCache from '@mui/docs/createEmotionCache'; import findActivePage from '@mui/docs/findActivePage'; import getProductInfoFromUrl from '@mui/docs/getProductInfoFromUrl'; -import { AnalyticsProvider } from 'docs/src/modules/components/AnalyticsProvider'; -import { DocsProvider } from '@mui/docs/DocsProvider'; import { mapTranslations } from '@mui/docs/i18n'; +import joyPkgJson from '@mui/joy/package.json'; +import { extendTheme, useColorScheme as useJoyColorScheme } from '@mui/joy/styles'; +import GlobalStyles from '@mui/material/GlobalStyles'; +import materialPkgJson from '@mui/material/package.json'; +import systemPkgJson from '@mui/system/package.json'; +import { LicenseInfo } from '@mui/x-license'; +import docsInfraPages from 'docs/data/docs-infra/pages'; +import generalDocsPages from 'docs/data/docs/pages'; +import joyPages from 'docs/data/joy/pages'; +import materialPages from 'docs/data/material/pages'; +import systemPages from 'docs/data/system/pages'; +import { BrandingCssThemeProvider } from 'docs/src/BrandingCssVarsProvider'; import SvgMuiLogomark, { muiSvgLogoString, muiSvgWordmarkString, } from 'docs/src/icons/SvgMuiLogomark'; -import './global.css'; -import '../public/static/components-gallery/base-theme.css'; +import { loadCSS } from 'fg-loadcss'; +import NextHead from 'next/head'; +import { useRouter } from 'next/router'; +import PropTypes from 'prop-types'; +import * as React from 'react'; import * as config from '../config'; - -export { fontClasses } from '@mui/docs/nextFonts'; +import '../public/static/components-gallery/base-theme.css'; +import './global.css'; // Remove the license warning from demonstration purposes LicenseInfo.setLicenseKey(process.env.NEXT_PUBLIC_MUI_LICENSE); @@ -429,7 +428,7 @@ function AppWrapper(props) { - + {children} diff --git a/docs/pages/_document.js b/docs/pages/_document.js index e1fbfd469a9eee..9dff638542ce10 100644 --- a/docs/pages/_document.js +++ b/docs/pages/_document.js @@ -9,7 +9,7 @@ import JoyInitColorSchemeScript from '@mui/joy/InitColorSchemeScript'; import { pathnameToLanguage } from '@mui/docs/helpers'; import createEmotionCache from '@mui/docs/createEmotionCache'; import { getMetaThemeColor } from '@mui/docs/branding'; -import { fontClasses } from './_app'; +import { fontClasses } from '@mui/docs/nextFonts'; const PRODUCTION_GA = process.env.DEPLOY_ENV === 'production' || process.env.DEPLOY_ENV === 'staging'; diff --git a/docs/src/modules/components/AnalyticsProvider.tsx b/packages/mui-docs/src/AnalyticsProvider/AnalyticsProvider.tsx similarity index 91% rename from docs/src/modules/components/AnalyticsProvider.tsx rename to packages/mui-docs/src/AnalyticsProvider/AnalyticsProvider.tsx index 09c725d7429eed..22c64a7ba3e698 100644 --- a/docs/src/modules/components/AnalyticsProvider.tsx +++ b/packages/mui-docs/src/AnalyticsProvider/AnalyticsProvider.tsx @@ -10,7 +10,6 @@ import { alpha } from '@mui/system'; import Portal from '@mui/material/Portal'; import TrapFocus from '@mui/material/Unstable_TrapFocus'; import CookieOutlinedIcon from '@mui/icons-material/CookieOutlined'; -import { BrandingCssThemeProvider } from 'docs/src/BrandingCssVarsProvider'; const COOKIE_CONSENT_KEY = 'docs-cookie-consent'; @@ -96,9 +95,15 @@ export function CookieConsentDialog() { pointerEvents: 'auto', boxShadow: theme.shadows[2], zIndex: theme.zIndex.snackbar, - ...theme.applyDarkStyles({ - bgcolor: 'primaryDark.900', - }), + ...(theme.applyDarkStyles + ? theme.applyDarkStyles({ + bgcolor: 'primaryDark.900', + }) + : { + [theme.getColorSchemeSelector?.('dark') || '&.mode-dark']: { + bgcolor: 'primaryDark.900', + }, + }), })} > @@ -172,7 +177,15 @@ function updateGoogleConsent(hasAnalytics: boolean) { } } -export function AnalyticsProvider({ children }: { children: React.ReactNode }) { +export function AnalyticsProvider({ + children, + slots, +}: { + children: React.ReactNode; + slots?: { + PagesThemeContainer?: React.ElementType; + }; +}) { const [consentStatus, setConsentStatus] = useLocalStorageState(COOKIE_CONSENT_KEY, null); const doNotTrack = useDoNotTrack(); @@ -208,12 +221,14 @@ export function AnalyticsProvider({ children }: { children: React.ReactNode }) { [consentStatus, doNotTrack, needsConsent, setAnalyticsConsent, setEssentialOnly], ); + const PagesThemeContainer = slots?.PagesThemeContainer || React.Fragment; + return ( {children} - + - + ); } diff --git a/packages/mui-docs/src/AnalyticsProvider/index.ts b/packages/mui-docs/src/AnalyticsProvider/index.ts new file mode 100644 index 00000000000000..705893829ff820 --- /dev/null +++ b/packages/mui-docs/src/AnalyticsProvider/index.ts @@ -0,0 +1 @@ +export { AnalyticsProvider, useAnalyticsConsent, CookieConsentDialog } from './AnalyticsProvider'; diff --git a/docs/src/modules/components/GoogleAnalytics.js b/packages/mui-docs/src/GoogleAnalytics/GoogleAnalytics.tsx similarity index 84% rename from docs/src/modules/components/GoogleAnalytics.js rename to packages/mui-docs/src/GoogleAnalytics/GoogleAnalytics.tsx index d3fcff7652608f..23c64c7246b003 100644 --- a/docs/src/modules/components/GoogleAnalytics.js +++ b/packages/mui-docs/src/GoogleAnalytics/GoogleAnalytics.tsx @@ -14,15 +14,16 @@ import { ThemeOptionsContext } from '@mui/docs/ThemeContext'; // > // Foo // -function handleClick(event) { - let element = event.target; +function handleClick(event: PointerEvent) { + let el = event.target; - while (element && element !== document) { + while (el && el !== document) { + const element = el as HTMLElement; const category = element.getAttribute('data-ga-event-category'); // We reach a tracking element, no need to look higher in the dom tree. if (category) { - const split = parseFloat(element.getAttribute('data-ga-event-split')); + const split = parseFloat(element.getAttribute('data-ga-event-split') || ''); if (split && split < Math.random()) { return; @@ -35,7 +36,7 @@ function handleClick(event) { break; } - element = element.parentElement; + el = element.parentElement; } } @@ -54,21 +55,29 @@ function GoogleAnalytics() { } }, []); const router = useRouter(); - const timeout = React.useRef(); + const timeout = React.useRef(null); React.useEffect(() => { // Wait for the title to be updated. // React fires useEffect twice in dev mode - clearTimeout(timeout.current); + if (timeout.current) { + clearTimeout(timeout.current); + } timeout.current = setTimeout(() => { const { canonicalAsServer } = pathnameToLanguage(window.location.pathname); // https://developers.google.com/analytics/devguides/collection/ga4/views?client_type=gtag + const productIdMeta = document.querySelector( + 'meta[name="mui:productId"]', + ) as HTMLMetaElement | null; + const productCategoryIdMeta = document.querySelector( + 'meta[name="mui:productCategoryId"]', + ) as HTMLMetaElement | null; window.gtag('event', 'page_view', { page_title: document.title, page_location: canonicalAsServer, - productId: document.querySelector('meta[name="mui:productId"]').content, - productCategoryId: document.querySelector('meta[name="mui:productCategoryId"]').content, + productId: productIdMeta?.content, + productCategoryId: productCategoryIdMeta?.content, }); }); }, [router.route]); diff --git a/packages/mui-docs/src/GoogleAnalytics/index.ts b/packages/mui-docs/src/GoogleAnalytics/index.ts new file mode 100644 index 00000000000000..c722d745b4f8fe --- /dev/null +++ b/packages/mui-docs/src/GoogleAnalytics/index.ts @@ -0,0 +1 @@ +export { default } from './GoogleAnalytics'; From 1fe50e47d003e583c3328ffb3298b97e68df53c0 Mon Sep 17 00:00:00 2001 From: Brijesh Bittu <717550+brijeshb42@users.noreply.github.com> Date: Wed, 4 Mar 2026 15:53:40 +0530 Subject: [PATCH 4/5] Move _document to mui-docs and make styled-components setup optional --- docs/pages/_document.js | 207 +----------------- packages/mui-docs/package.json | 6 +- packages/mui-docs/src/Document/Document.tsx | 160 ++++++++++++++ .../mui-docs/src/Document/getInitialProps.tsx | 75 +++++++ packages/mui-docs/src/Document/index.ts | 2 + pnpm-lock.yaml | 3 + 6 files changed, 252 insertions(+), 201 deletions(-) create mode 100644 packages/mui-docs/src/Document/Document.tsx create mode 100644 packages/mui-docs/src/Document/getInitialProps.tsx create mode 100644 packages/mui-docs/src/Document/index.ts diff --git a/docs/pages/_document.js b/docs/pages/_document.js index 9dff638542ce10..06911d5dd2819b 100644 --- a/docs/pages/_document.js +++ b/docs/pages/_document.js @@ -1,208 +1,15 @@ -import * as React from 'react'; -import Script from 'next/script'; -import { documentGetInitialProps } from '@mui/material-nextjs/v13-pagesRouter'; -import { ServerStyleSheet } from 'styled-components'; -import Document, { Html, Head, Main, NextScript } from 'next/document'; -import GlobalStyles from '@mui/material/GlobalStyles'; -import MuiInitColorSchemeScript from '@mui/material/InitColorSchemeScript'; +import NextDocument from 'next/document'; +import { Document as MuiDocsDocument, createGetInitialProps } from '@mui/docs/Document'; import JoyInitColorSchemeScript from '@mui/joy/InitColorSchemeScript'; -import { pathnameToLanguage } from '@mui/docs/helpers'; -import createEmotionCache from '@mui/docs/createEmotionCache'; -import { getMetaThemeColor } from '@mui/docs/branding'; -import { fontClasses } from '@mui/docs/nextFonts'; -const PRODUCTION_GA = - process.env.DEPLOY_ENV === 'production' || process.env.DEPLOY_ENV === 'staging'; +export default class MuiDocument extends NextDocument { + static getInitialProps = createGetInitialProps({ setupStyledComponents: true }); -const GOOGLE_ANALYTICS_ID_V4 = PRODUCTION_GA ? 'G-5NXDQLC2ZK' : 'G-XJ83JQEK7J'; -const APOLLO_TRACKING_ID = PRODUCTION_GA ? '691c2e920c5e20000d7801b6' : 'dev-id'; - -export default class MyDocument extends Document { render() { - const { canonicalAsServer, userLanguage } = this.props; - return ( - - - {/* - manifest.json provides metadata used when your web app is added to the - homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/ - */} - - {/* PWA primary color */} - - - - {/* iOS Icon */} - - {/* SEO */} - - - - - - - -

-