diff --git a/.browserslistrc b/.browserslistrc index 6ab4c0c15806ec..6bf6f0e0e1e601 100644 --- a/.browserslistrc +++ b/.browserslistrc @@ -72,66 +72,6 @@ safari 15.4 samsung 23 samsung 22 -[legacy] -ie 11 -and_chr 122 -and_chr 121 -and_ff 123 -and_ff 122 -and_qq 14.9 -and_uc 15.5 -android 122 -android 121 -chrome 122 -chrome 121 -chrome 120 -chrome 119 -chrome 109 -edge 122 -edge 121 -firefox 123 -firefox 122 -firefox 115 -ios_saf 17.4 -ios_saf 17.3 -ios_saf 17.2 -ios_saf 17.1 -ios_saf 17.0 -ios_saf 16.6-16.7 -ios_saf 16.5 -ios_saf 16.4 -ios_saf 16.3 -ios_saf 16.2 -ios_saf 16.1 -ios_saf 16.0 -ios_saf 15.6-15.8 -ios_saf 15.5 -ios_saf 15.4 -kaios 3.0-3.1 -kaios 2.5 -op_mini all -op_mob 80 -opera 108 -opera 107 -opera 106 -safari 17.4 -safari 17.3 -safari 17.2 -safari 17.1 -safari 17.0 -safari 16.6 -safari 16.5 -safari 16.4 -safari 16.3 -safari 16.2 -safari 16.1 -safari 16.0 -safari 15.6 -safari 15.5 -safari 15.4 -samsung 23 -samsung 22 - # snapshot of `npx browserslist "maintained node versions"` # On update check all #stable-snapshot markers [node] diff --git a/.eslintrc.js b/.eslintrc.js index a06ac35ae3f3ae..a75d1e007728ff 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -164,7 +164,7 @@ module.exports = { 'react/state-in-constructor': 'off', // stylistic opinion. For conditional assignment we want it outside, otherwise as static 'react/static-property-placement': 'off', - // noopener is enough, no IE 11 support + // noopener is enough // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-target-blank.md#rule-options 'react/jsx-no-target-blank': ['error', { allowReferrer: true }], diff --git a/CHANGELOG.md b/CHANGELOG.md index b359e9a43437de..1590d764bc466b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,78 @@ # [Versions](https://mui.com/versions/) +## v6.0.0-alpha.3 + + + +_Apr 17, 2024_ + +A big thanks to the 24 contributors who made this release possible. Here are some highlights ✨: + +- 🔥 Converted 5 more Material UI components to use Pigment CSS. +- 🚀 Added container queries utility to the `@mui/system` package (#41674) @siriwatknp. + +### `@mui/material@6.0.0-alpha.3` + +- Convert `LinearProgress` to support Pigment CSS (#41816) @siriwatknp +- [Dialog] Prevent onClick on the root element from being overwritten (#41881) @ryanburr +- [FloatingActionButton] Convert to support CSS extraction (#41851) @gijsbotje +- Convert `CircularProgress` to support Pigment CSS (#41776) @siriwatknp +- [PaginationItem] Convert to support CSS extraction (#41848) @gijsbotje +- [StepConnector] deprecate composed classes (#41740) @sai6855 +- [StepLabel] Deprecate `StepIconComponent`, `StepIconProps` (#41835) @sai6855 +- [ToggleButton] Convert to support CSS extraction (#41782) @lhilgert9 +- [ToggleButtonGroup] Deprecate composed classes (#41288) @sai6855 +- [Typography] Fix Typography inherit variant styles (#41308) @kealjones-wk + +### `@mui/system@6.0.0-alpha.3` + +- Add container queries utility (#41674) @siriwatknp + +### `@mui/codemod@6.0.0-alpha.3` + +- Add styled v6 transformation (#41743) @siriwatknp + +### `@mui/joy@5.0.0-beta.36` + +- [Button] Disable text highlighting (#41902) @mithun522 + +### `@pigment-css/react@0.0.7` + +- Patch WyW's WeakRef usage (#41909) @DiegoAndai +- Implement sx transform for system components (#41861) @brijeshb42 + +### Docs + +- [material-ui] Add Connect-related content (#40848) @danilo-leal +- [material-ui] Fix credit comment typo (#41872) @aarongarciah +- [material-ui] Remove Data Grid v7 beta callout (#41839) @cherniavskii +- [material-ui] Add stray design tweaks to free templates (#41696) @zanivan +- [material-ui] Simplify components styling on templates (#41845) @zanivan +- [material-ui][Button] Add `onChange` event handler to file upload example (#41863) @aarongarciah +- [material-ui] Fix import statement in migration guide (#41852) @sai6855 +- Fix 301 redirection @oliviertassinari +- Fix format git diff regression (#41882) @oliviertassinari +- Fix small SEO issues @oliviertassinari +- [pigment-css] Fix README typos (#41870) @MohammadShehadeh + +### Core + +- Begin removing IE 11-related code (#41709) @iammminzzy +- [blog] Add post to introduce the Connect plugin (#41763) @danilo-leal +- [code-infra] Fix require.context with aliases (#41682) @Janpot +- [code-infra] Allow customizing hooks imports in API docs generator (#41828) @michaldudak +- [codemod] Add utils for `*Component` and `*Props` props deprecations (#41685) @DiegoAndai +- Replace bundle size reporter filter (#38979) @Janpot +- [docs-infra] Make the whole header clickable (#39603) @MoazMirza-13 +- [docs-infra] Improve demo container and related components design (#41827) @danilo-leal +- [docs-infra] Use edge function for card generation (#41188) (#41836) @alexfauquette +- [docs-infra] Fix code block layout shift (#41917) @oliviertassinari +- [docs-infra] Fine-tune the OG card image design (#41862) @danilo-leal +- [docs-infra] Fix markdown version for material (#41908) @alexfauquette +- [docs-infra] Support multiple tabs in demos (#40901) @bharatkashyap + +All contributors of this release in alphabetical order: @aarongarciah, @alexfauquette, @bharatkashyap, @brijeshb42, @cherniavskii, @danilo-leal, @DiegoAndai, @EyaOuenniche, @gijsbotje, @iammminzzy, @Janpot, @kealjones-wk, @lhilgert9, @magnimarels, @michaldudak, @mithun522, @mnajdova, @MoazMirza-13, @MohammadShehadeh, @oliviertassinari, @ryanburr, @sai6855, @siriwatknp, @zanivan + ## v6.0.0-alpha.2 diff --git a/apps/pigment-css-next-app/src/app/material-ui/react-radio-button/page.tsx b/apps/pigment-css-next-app/src/app/material-ui/react-radio-button/page.tsx new file mode 100644 index 00000000000000..dda8ef7fe821b6 --- /dev/null +++ b/apps/pigment-css-next-app/src/app/material-ui/react-radio-button/page.tsx @@ -0,0 +1,79 @@ +'use client'; +import * as React from 'react'; +import ColorRadioButtons from '../../../../../../docs/data/material/components/radio-buttons/ColorRadioButtons'; +import ControlledRadioButtonsGroup from '../../../../../../docs/data/material/components/radio-buttons/ControlledRadioButtonsGroup'; +import CustomizedRadios from '../../../../../../docs/data/material/components/radio-buttons/CustomizedRadios'; +import ErrorRadios from '../../../../../../docs/data/material/components/radio-buttons/ErrorRadios'; +import FormControlLabelPlacement from '../../../../../../docs/data/material/components/radio-buttons/FormControlLabelPlacement'; +import RadioButtonsComponent from '../../../../../../docs/data/material/components/radio-buttons/RadioButtons'; +import RadioButtonsGroup from '../../../../../../docs/data/material/components/radio-buttons/RadioButtonsGroup'; +import RowRadioButtonsGroup from '../../../../../../docs/data/material/components/radio-buttons/RowRadioButtonsGroup'; +import SizeRadioButtons from '../../../../../../docs/data/material/components/radio-buttons/SizeRadioButtons'; +import UseRadioGroup from '../../../../../../docs/data/material/components/radio-buttons/UseRadioGroup'; + +export default function RadioButtons() { + return ( + +
+

Color Radio Buttons

+
+ +
+
+
+

Controlled Radio Buttons Group

+
+ +
+
+
+

Customized Radios

+
+ +
+
+
+

Error Radios

+
+ +
+
+
+

Form Control Label Placement

+
+ +
+
+
+

Radio Buttons

+
+ +
+
+
+

Radio Buttons Group

+
+ +
+
+
+

Row Radio Buttons Group

+
+ +
+
+
+

Size Radio Buttons

+
+ +
+
+
+

Use Radio Group

+
+ +
+
+
+ ); +} diff --git a/apps/pigment-css-next-app/src/app/material-ui/react-stepper/page.tsx b/apps/pigment-css-next-app/src/app/material-ui/react-stepper/page.tsx index 81bc13081eeb64..8e135c3b896a2e 100644 --- a/apps/pigment-css-next-app/src/app/material-ui/react-stepper/page.tsx +++ b/apps/pigment-css-next-app/src/app/material-ui/react-stepper/page.tsx @@ -7,7 +7,6 @@ import HorizontalLinearStepper from '../../../../../../docs/data/material/compon import HorizontalNonLinearStepper from '../../../../../../docs/data/material/components/steppers/HorizontalNonLinearStepper'; import HorizontalStepperWithError from '../../../../../../docs/data/material/components/steppers/HorizontalStepperWithError'; import ProgressMobileStepper from '../../../../../../docs/data/material/components/steppers/ProgressMobileStepper'; -import SwipeableTextMobileStepper from '../../../../../../docs/data/material/components/steppers/SwipeableTextMobileStepper'; import TextMobileStepper from '../../../../../../docs/data/material/components/steppers/TextMobileStepper'; import VerticalLinearStepper from '../../../../../../docs/data/material/components/steppers/VerticalLinearStepper'; @@ -56,12 +55,6 @@ export default function Steppers() { -
-

Swipeable Text Mobile Stepper

-
- -
-

Text Mobile Stepper

diff --git a/apps/pigment-css-vite-app/src/pages/material-ui/react-radio-button.tsx b/apps/pigment-css-vite-app/src/pages/material-ui/react-radio-button.tsx new file mode 100644 index 00000000000000..138e0386c4446c --- /dev/null +++ b/apps/pigment-css-vite-app/src/pages/material-ui/react-radio-button.tsx @@ -0,0 +1,80 @@ +import * as React from 'react'; +import MaterialUILayout from '../../Layout'; +import ColorRadioButtons from '../../../../../docs/data/material/components/radio-buttons/ColorRadioButtons.tsx'; +import ControlledRadioButtonsGroup from '../../../../../docs/data/material/components/radio-buttons/ControlledRadioButtonsGroup.tsx'; +import CustomizedRadios from '../../../../../docs/data/material/components/radio-buttons/CustomizedRadios.tsx'; +import ErrorRadios from '../../../../../docs/data/material/components/radio-buttons/ErrorRadios.tsx'; +import FormControlLabelPlacement from '../../../../../docs/data/material/components/radio-buttons/FormControlLabelPlacement.tsx'; +import RadioButtonsComponent from '../../../../../docs/data/material/components/radio-buttons/RadioButtons.tsx'; +import RadioButtonsGroup from '../../../../../docs/data/material/components/radio-buttons/RadioButtonsGroup.tsx'; +import RowRadioButtonsGroup from '../../../../../docs/data/material/components/radio-buttons/RowRadioButtonsGroup.tsx'; +import SizeRadioButtons from '../../../../../docs/data/material/components/radio-buttons/SizeRadioButtons.tsx'; +import UseRadioGroup from '../../../../../docs/data/material/components/radio-buttons/UseRadioGroup.tsx'; + +export default function RadioButtons() { + return ( + +

RadioButtons

+
+

Color Radio Buttons

+
+ +
+
+
+

Controlled Radio Buttons Group

+
+ +
+
+
+

Customized Radios

+
+ +
+
+
+

Error Radios

+
+ +
+
+
+

Form Control Label Placement

+
+ +
+
+
+

Radio Buttons

+
+ +
+
+
+

Radio Buttons Group

+
+ +
+
+
+

Row Radio Buttons Group

+
+ +
+
+
+

Size Radio Buttons

+
+ +
+
+
+

Use Radio Group

+
+ +
+
+
+ ); +} diff --git a/apps/pigment-css-vite-app/src/pages/material-ui/react-stepper.tsx b/apps/pigment-css-vite-app/src/pages/material-ui/react-stepper.tsx index 5f9cc1d0e683d6..5a080f5f941d29 100644 --- a/apps/pigment-css-vite-app/src/pages/material-ui/react-stepper.tsx +++ b/apps/pigment-css-vite-app/src/pages/material-ui/react-stepper.tsx @@ -7,7 +7,6 @@ import HorizontalLinearStepper from '../../../../../docs/data/material/component import HorizontalNonLinearStepper from '../../../../../docs/data/material/components/steppers/HorizontalNonLinearStepper.tsx'; import HorizontalStepperWithError from '../../../../../docs/data/material/components/steppers/HorizontalStepperWithError.tsx'; import ProgressMobileStepper from '../../../../../docs/data/material/components/steppers/ProgressMobileStepper.tsx'; -import SwipeableTextMobileStepper from '../../../../../docs/data/material/components/steppers/SwipeableTextMobileStepper.tsx'; import TextMobileStepper from '../../../../../docs/data/material/components/steppers/TextMobileStepper.tsx'; import VerticalLinearStepper from '../../../../../docs/data/material/components/steppers/VerticalLinearStepper.tsx'; @@ -57,12 +56,6 @@ export default function Steppers() {
-
-

Swipeable Text Mobile Stepper

-
- -
-

Text Mobile Stepper

diff --git a/babel.config.js b/babel.config.js index 48ca2abea4ce50..ad22418643bf84 100644 --- a/babel.config.js +++ b/babel.config.js @@ -13,7 +13,7 @@ const productionPlugins = [ ]; module.exports = function getBabelConfig(api) { - const useESModules = api.env(['regressions', 'legacy', 'modern', 'stable', 'rollup']); + const useESModules = api.env(['regressions', 'modern', 'stable', 'rollup']); const defaultAlias = { '@mui/material': resolveAliasPath('./packages/mui-material/src'), @@ -153,12 +153,6 @@ module.exports = function getBabelConfig(api) { ], ], }, - legacy: { - plugins: [ - // IE11 support - '@babel/plugin-transform-object-assign', - ], - }, test: { sourceMaps: 'both', plugins: [ diff --git a/docs/babel.config.js b/docs/babel.config.js index 57d4fab1b602af..1ccf95cfbb1b80 100644 --- a/docs/babel.config.js +++ b/docs/babel.config.js @@ -32,8 +32,6 @@ module.exports = { }, ], 'babel-plugin-optimize-clsx', - // for IE11 support - '@babel/plugin-transform-object-assign', ], ignore: [/@babel[\\|/]runtime/], // Fix a Windows issue. env: { diff --git a/docs/data/joy/components/accordion/AccordionTransition.js b/docs/data/joy/components/accordion/AccordionTransition.js index 15908702f1506d..97d04db1d8f0c0 100644 --- a/docs/data/joy/components/accordion/AccordionTransition.js +++ b/docs/data/joy/components/accordion/AccordionTransition.js @@ -8,7 +8,7 @@ import RadioGroup from '@mui/joy/RadioGroup'; import Radio from '@mui/joy/Radio'; import Stack from '@mui/joy/Stack'; import Typography from '@mui/joy/Typography'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; import { BrandingProvider } from '@mui/docs/branding'; export default function AccordionTransition() { diff --git a/docs/data/joy/components/badge/BadgeAlignment.js b/docs/data/joy/components/badge/BadgeAlignment.js index 4d0c4ac31ef6ad..4d634732314b0d 100644 --- a/docs/data/joy/components/badge/BadgeAlignment.js +++ b/docs/data/joy/components/badge/BadgeAlignment.js @@ -5,7 +5,7 @@ import Box from '@mui/joy/Box'; import IconButton from '@mui/joy/IconButton'; import ArrowUpward from '@mui/icons-material/ArrowUpward'; import ArrowDownward from '@mui/icons-material/ArrowDownward'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; import { BrandingProvider } from '@mui/docs/branding'; export default function BadgeAlignment() { diff --git a/docs/data/joy/components/badge/BadgeAlignment.tsx b/docs/data/joy/components/badge/BadgeAlignment.tsx index 26cef0321dd2f4..f63d48b4b9ce34 100644 --- a/docs/data/joy/components/badge/BadgeAlignment.tsx +++ b/docs/data/joy/components/badge/BadgeAlignment.tsx @@ -5,7 +5,7 @@ import Box from '@mui/joy/Box'; import IconButton from '@mui/joy/IconButton'; import ArrowUpward from '@mui/icons-material/ArrowUpward'; import ArrowDownward from '@mui/icons-material/ArrowDownward'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; import { BrandingProvider } from '@mui/docs/branding'; export default function BadgeAlignment() { diff --git a/docs/data/joy/components/grid/InteractiveGrid.js b/docs/data/joy/components/grid/InteractiveGrid.js index 6752884b6f1483..dcd42d773ad641 100644 --- a/docs/data/joy/components/grid/InteractiveGrid.js +++ b/docs/data/joy/components/grid/InteractiveGrid.js @@ -7,7 +7,7 @@ import Radio from '@mui/joy/Radio'; import Sheet from '@mui/joy/Sheet'; import { BrandingProvider } from '@mui/docs/branding'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; export default function InteractiveGrid() { const [direction, setDirection] = React.useState('row'); diff --git a/docs/data/joy/components/grid/InteractiveGrid.tsx b/docs/data/joy/components/grid/InteractiveGrid.tsx index 8059be0f4b3260..14875c640d8a4a 100644 --- a/docs/data/joy/components/grid/InteractiveGrid.tsx +++ b/docs/data/joy/components/grid/InteractiveGrid.tsx @@ -7,7 +7,7 @@ import Radio from '@mui/joy/Radio'; import Sheet from '@mui/joy/Sheet'; import { GridDirection } from '@mui/system'; import { BrandingProvider } from '@mui/docs/branding'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; type GridItemsAlignment = | 'flex-start' diff --git a/docs/data/joy/components/grid/SpacingGrid.js b/docs/data/joy/components/grid/SpacingGrid.js index 20971a1813de88..56bf0c72b1630d 100644 --- a/docs/data/joy/components/grid/SpacingGrid.js +++ b/docs/data/joy/components/grid/SpacingGrid.js @@ -5,7 +5,7 @@ import FormControl from '@mui/joy/FormControl'; import RadioGroup from '@mui/joy/RadioGroup'; import Radio from '@mui/joy/Radio'; import Sheet from '@mui/joy/Sheet'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; import { BrandingProvider } from '@mui/docs/branding'; export default function SpacingGrid() { diff --git a/docs/data/joy/components/grid/SpacingGrid.tsx b/docs/data/joy/components/grid/SpacingGrid.tsx index ebb3466624480a..027fd1666a7b17 100644 --- a/docs/data/joy/components/grid/SpacingGrid.tsx +++ b/docs/data/joy/components/grid/SpacingGrid.tsx @@ -5,7 +5,7 @@ import FormControl from '@mui/joy/FormControl'; import RadioGroup from '@mui/joy/RadioGroup'; import Radio from '@mui/joy/Radio'; import Sheet from '@mui/joy/Sheet'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; import { BrandingProvider } from '@mui/docs/branding'; export default function SpacingGrid() { diff --git a/docs/data/joy/components/stack/InteractiveStack.js b/docs/data/joy/components/stack/InteractiveStack.js index d5142c84f95783..7243fcf4fc30b4 100644 --- a/docs/data/joy/components/stack/InteractiveStack.js +++ b/docs/data/joy/components/stack/InteractiveStack.js @@ -7,7 +7,7 @@ import RadioGroup from '@mui/joy/RadioGroup'; import Radio from '@mui/joy/Radio'; import Stack from '@mui/joy/Stack'; import { styled } from '@mui/joy/styles'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; import { BrandingProvider } from '@mui/docs/branding'; const Item = styled(Sheet)(({ theme }) => ({ diff --git a/docs/data/joy/components/stack/InteractiveStack.tsx b/docs/data/joy/components/stack/InteractiveStack.tsx index 971adbb6a0f9c3..2f6ab92a887fb2 100644 --- a/docs/data/joy/components/stack/InteractiveStack.tsx +++ b/docs/data/joy/components/stack/InteractiveStack.tsx @@ -7,7 +7,7 @@ import RadioGroup from '@mui/joy/RadioGroup'; import Radio from '@mui/joy/Radio'; import Stack, { StackProps } from '@mui/joy/Stack'; import { styled } from '@mui/joy/styles'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; import { BrandingProvider } from '@mui/docs/branding'; const Item = styled(Sheet)(({ theme }) => ({ diff --git a/docs/data/joy/components/table/TableSortAndSelection.js b/docs/data/joy/components/table/TableSortAndSelection.js index 2455a21333b4cf..c7649aa9609b6d 100644 --- a/docs/data/joy/components/table/TableSortAndSelection.js +++ b/docs/data/joy/components/table/TableSortAndSelection.js @@ -65,22 +65,6 @@ function getComparator(order, orderBy) { : (a, b) => -descendingComparator(a, b, orderBy); } -// Since 2020 all major browsers ensure sort stability with Array.prototype.sort(). -// stableSort() brings sort stability to non-modern browsers (notably IE11). If you -// only support modern browsers you can replace stableSort(exampleArray, exampleComparator) -// with exampleArray.slice().sort(exampleComparator) -function stableSort(array, comparator) { - const stabilizedThis = array.map((el, index) => [el, index]); - stabilizedThis.sort((a, b) => { - const order = comparator(a[0], b[0]); - if (order !== 0) { - return order; - } - return a[1] - b[1]; - }); - return stabilizedThis.map((el) => el[0]); -} - const headCells = [ { id: 'name', @@ -348,7 +332,8 @@ export default function TableSortAndSelection() { rowCount={rows.length} /> - {stableSort(rows, getComparator(order, orderBy)) + {[...rows] + .sort(getComparator(order, orderBy)) .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) .map((row, index) => { const isItemSelected = isSelected(row.name); diff --git a/docs/data/joy/components/table/TableSortAndSelection.tsx b/docs/data/joy/components/table/TableSortAndSelection.tsx index f063700890b412..06026b6cfa0758 100644 --- a/docs/data/joy/components/table/TableSortAndSelection.tsx +++ b/docs/data/joy/components/table/TableSortAndSelection.tsx @@ -94,22 +94,6 @@ function getComparator( : (a, b) => -descendingComparator(a, b, orderBy); } -// Since 2020 all major browsers ensure sort stability with Array.prototype.sort(). -// stableSort() brings sort stability to non-modern browsers (notably IE11). If you -// only support modern browsers you can replace stableSort(exampleArray, exampleComparator) -// with exampleArray.slice().sort(exampleComparator) -function stableSort(array: readonly T[], comparator: (a: T, b: T) => number) { - const stabilizedThis = array.map((el, index) => [el, index] as [T, number]); - stabilizedThis.sort((a, b) => { - const order = comparator(a[0], b[0]); - if (order !== 0) { - return order; - } - return a[1] - b[1]; - }); - return stabilizedThis.map((el) => el[0]); -} - interface HeadCell { disablePadding: boolean; id: keyof Data; @@ -390,7 +374,8 @@ export default function TableSortAndSelection() { rowCount={rows.length} /> - {stableSort(rows, getComparator(order, orderBy)) + {[...rows] + .sort(getComparator(order, orderBy)) .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) .map((row, index) => { const isItemSelected = isSelected(row.name); diff --git a/docs/data/joy/customization/approaches/ButtonThemes.js b/docs/data/joy/customization/approaches/ButtonThemes.js index ee359cacdf3162..e5eb79a876b3fc 100644 --- a/docs/data/joy/customization/approaches/ButtonThemes.js +++ b/docs/data/joy/customization/approaches/ButtonThemes.js @@ -5,7 +5,7 @@ import Button from '@mui/joy/Button'; import FormLabel from '@mui/joy/FormLabel'; import Select from '@mui/joy/Select'; import Option from '@mui/joy/Option'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; import { BrandingProvider } from '@mui/docs/branding'; const githubTheme = extendTheme({ diff --git a/docs/data/joy/getting-started/templates/order-dashboard/components/OrderTable.tsx b/docs/data/joy/getting-started/templates/order-dashboard/components/OrderTable.tsx index d01260b9fcd5d2..06c900a8d05ae1 100644 --- a/docs/data/joy/getting-started/templates/order-dashboard/components/OrderTable.tsx +++ b/docs/data/joy/getting-started/templates/order-dashboard/components/OrderTable.tsx @@ -242,22 +242,6 @@ function getComparator( : (a, b) => -descendingComparator(a, b, orderBy); } -// Since 2020 all major browsers ensure sort stability with Array.prototype.sort(). -// stableSort() brings sort stability to non-modern browsers (notably IE11). If you -// only support modern browsers you can replace stableSort(exampleArray, exampleComparator) -// with exampleArray.slice().sort(exampleComparator) -function stableSort(array: readonly T[], comparator: (a: T, b: T) => number) { - const stabilizedThis = array.map((el, index) => [el, index] as [T, number]); - stabilizedThis.sort((a, b) => { - const order = comparator(a[0], b[0]); - if (order !== 0) { - return order; - } - return a[1] - b[1]; - }); - return stabilizedThis.map((el) => el[0]); -} - function RowMenu() { return ( @@ -451,7 +435,7 @@ export default function OrderTable() { - {stableSort(rows, getComparator(order, 'id')).map((row) => ( + {[...rows].sort(getComparator(order, 'id')).map((row) => ( ); } - -// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top -const top100Films = [ - { label: 'The Shawshank Redemption', year: 1994 }, - { label: 'The Godfather', year: 1972 }, - { label: 'The Godfather: Part II', year: 1974 }, - { label: 'The Dark Knight', year: 2008 }, - { label: '12 Angry Men', year: 1957 }, - { label: "Schindler's List", year: 1993 }, - { label: 'Pulp Fiction', year: 1994 }, - { - label: 'The Lord of the Rings: The Return of the King', - year: 2003, - }, - { label: 'The Good, the Bad and the Ugly', year: 1966 }, - { label: 'Fight Club', year: 1999 }, - { - label: 'The Lord of the Rings: The Fellowship of the Ring', - year: 2001, - }, - { - label: 'Star Wars: Episode V - The Empire Strikes Back', - year: 1980, - }, - { label: 'Forrest Gump', year: 1994 }, - { label: 'Inception', year: 2010 }, - { - label: 'The Lord of the Rings: The Two Towers', - year: 2002, - }, - { label: "One Flew Over the Cuckoo's Nest", year: 1975 }, - { label: 'Goodfellas', year: 1990 }, - { label: 'The Matrix', year: 1999 }, - { label: 'Seven Samurai', year: 1954 }, - { - label: 'Star Wars: Episode IV - A New Hope', - year: 1977, - }, - { label: 'City of God', year: 2002 }, - { label: 'Se7en', year: 1995 }, - { label: 'The Silence of the Lambs', year: 1991 }, - { label: "It's a Wonderful Life", year: 1946 }, - { label: 'Life Is Beautiful', year: 1997 }, - { label: 'The Usual Suspects', year: 1995 }, - { label: 'Léon: The Professional', year: 1994 }, - { label: 'Spirited Away', year: 2001 }, - { label: 'Saving Private Ryan', year: 1998 }, - { label: 'Once Upon a Time in the West', year: 1968 }, - { label: 'American History X', year: 1998 }, - { label: 'Interstellar', year: 2014 }, - { label: 'Casablanca', year: 1942 }, - { label: 'City Lights', year: 1931 }, - { label: 'Psycho', year: 1960 }, - { label: 'The Green Mile', year: 1999 }, - { label: 'The Intouchables', year: 2011 }, - { label: 'Modern Times', year: 1936 }, - { label: 'Raiders of the Lost Ark', year: 1981 }, - { label: 'Rear Window', year: 1954 }, - { label: 'The Pianist', year: 2002 }, - { label: 'The Departed', year: 2006 }, - { label: 'Terminator 2: Judgment Day', year: 1991 }, - { label: 'Back to the Future', year: 1985 }, - { label: 'Whiplash', year: 2014 }, - { label: 'Gladiator', year: 2000 }, - { label: 'Memento', year: 2000 }, - { label: 'The Prestige', year: 2006 }, - { label: 'The Lion King', year: 1994 }, - { label: 'Apocalypse Now', year: 1979 }, - { label: 'Alien', year: 1979 }, - { label: 'Sunset Boulevard', year: 1950 }, - { - label: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', - year: 1964, - }, - { label: 'The Great Dictator', year: 1940 }, - { label: 'Cinema Paradiso', year: 1988 }, - { label: 'The Lives of Others', year: 2006 }, - { label: 'Grave of the Fireflies', year: 1988 }, - { label: 'Paths of Glory', year: 1957 }, - { label: 'Django Unchained', year: 2012 }, - { label: 'The Shining', year: 1980 }, - { label: 'WALL·E', year: 2008 }, - { label: 'American Beauty', year: 1999 }, - { label: 'The Dark Knight Rises', year: 2012 }, - { label: 'Princess Mononoke', year: 1997 }, - { label: 'Aliens', year: 1986 }, - { label: 'Oldboy', year: 2003 }, - { label: 'Once Upon a Time in America', year: 1984 }, - { label: 'Witness for the Prosecution', year: 1957 }, - { label: 'Das Boot', year: 1981 }, - { label: 'Citizen Kane', year: 1941 }, - { label: 'North by Northwest', year: 1959 }, - { label: 'Vertigo', year: 1958 }, - { - label: 'Star Wars: Episode VI - Return of the Jedi', - year: 1983, - }, - { label: 'Reservoir Dogs', year: 1992 }, - { label: 'Braveheart', year: 1995 }, - { label: 'M', year: 1931 }, - { label: 'Requiem for a Dream', year: 2000 }, - { label: 'Amélie', year: 2001 }, - { label: 'A Clockwork Orange', year: 1971 }, - { label: 'Like Stars on Earth', year: 2007 }, - { label: 'Taxi Driver', year: 1976 }, - { label: 'Lawrence of Arabia', year: 1962 }, - { label: 'Double Indemnity', year: 1944 }, - { - label: 'Eternal Sunshine of the Spotless Mind', - year: 2004, - }, - { label: 'Amadeus', year: 1984 }, - { label: 'To Kill a Mockingbird', year: 1962 }, - { label: 'Toy Story 3', year: 2010 }, - { label: 'Logan', year: 2017 }, - { label: 'Full Metal Jacket', year: 1987 }, - { label: 'Dangal', year: 2016 }, - { label: 'The Sting', year: 1973 }, - { label: '2001: A Space Odyssey', year: 1968 }, - { label: "Singin' in the Rain", year: 1952 }, - { label: 'Toy Story', year: 1995 }, - { label: 'Bicycle Thieves', year: 1948 }, - { label: 'The Kid', year: 1921 }, - { label: 'Inglourious Basterds', year: 2009 }, - { label: 'Snatch', year: 2000 }, - { label: '3 Idiots', year: 2009 }, - { label: 'Monty Python and the Holy Grail', year: 1975 }, -]; diff --git a/docs/data/material/components/autocomplete/ComboBox.tsx b/docs/data/material/components/autocomplete/ComboBox.tsx index 4e515937746cb4..ceeb0eb96834a4 100644 --- a/docs/data/material/components/autocomplete/ComboBox.tsx +++ b/docs/data/material/components/autocomplete/ComboBox.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import TextField from '@mui/material/TextField'; import Autocomplete from '@mui/material/Autocomplete'; +import top100Films from './top100Films'; export default function ComboBox() { return ( @@ -13,131 +14,3 @@ export default function ComboBox() { /> ); } - -// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top -const top100Films = [ - { label: 'The Shawshank Redemption', year: 1994 }, - { label: 'The Godfather', year: 1972 }, - { label: 'The Godfather: Part II', year: 1974 }, - { label: 'The Dark Knight', year: 2008 }, - { label: '12 Angry Men', year: 1957 }, - { label: "Schindler's List", year: 1993 }, - { label: 'Pulp Fiction', year: 1994 }, - { - label: 'The Lord of the Rings: The Return of the King', - year: 2003, - }, - { label: 'The Good, the Bad and the Ugly', year: 1966 }, - { label: 'Fight Club', year: 1999 }, - { - label: 'The Lord of the Rings: The Fellowship of the Ring', - year: 2001, - }, - { - label: 'Star Wars: Episode V - The Empire Strikes Back', - year: 1980, - }, - { label: 'Forrest Gump', year: 1994 }, - { label: 'Inception', year: 2010 }, - { - label: 'The Lord of the Rings: The Two Towers', - year: 2002, - }, - { label: "One Flew Over the Cuckoo's Nest", year: 1975 }, - { label: 'Goodfellas', year: 1990 }, - { label: 'The Matrix', year: 1999 }, - { label: 'Seven Samurai', year: 1954 }, - { - label: 'Star Wars: Episode IV - A New Hope', - year: 1977, - }, - { label: 'City of God', year: 2002 }, - { label: 'Se7en', year: 1995 }, - { label: 'The Silence of the Lambs', year: 1991 }, - { label: "It's a Wonderful Life", year: 1946 }, - { label: 'Life Is Beautiful', year: 1997 }, - { label: 'The Usual Suspects', year: 1995 }, - { label: 'Léon: The Professional', year: 1994 }, - { label: 'Spirited Away', year: 2001 }, - { label: 'Saving Private Ryan', year: 1998 }, - { label: 'Once Upon a Time in the West', year: 1968 }, - { label: 'American History X', year: 1998 }, - { label: 'Interstellar', year: 2014 }, - { label: 'Casablanca', year: 1942 }, - { label: 'City Lights', year: 1931 }, - { label: 'Psycho', year: 1960 }, - { label: 'The Green Mile', year: 1999 }, - { label: 'The Intouchables', year: 2011 }, - { label: 'Modern Times', year: 1936 }, - { label: 'Raiders of the Lost Ark', year: 1981 }, - { label: 'Rear Window', year: 1954 }, - { label: 'The Pianist', year: 2002 }, - { label: 'The Departed', year: 2006 }, - { label: 'Terminator 2: Judgment Day', year: 1991 }, - { label: 'Back to the Future', year: 1985 }, - { label: 'Whiplash', year: 2014 }, - { label: 'Gladiator', year: 2000 }, - { label: 'Memento', year: 2000 }, - { label: 'The Prestige', year: 2006 }, - { label: 'The Lion King', year: 1994 }, - { label: 'Apocalypse Now', year: 1979 }, - { label: 'Alien', year: 1979 }, - { label: 'Sunset Boulevard', year: 1950 }, - { - label: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', - year: 1964, - }, - { label: 'The Great Dictator', year: 1940 }, - { label: 'Cinema Paradiso', year: 1988 }, - { label: 'The Lives of Others', year: 2006 }, - { label: 'Grave of the Fireflies', year: 1988 }, - { label: 'Paths of Glory', year: 1957 }, - { label: 'Django Unchained', year: 2012 }, - { label: 'The Shining', year: 1980 }, - { label: 'WALL·E', year: 2008 }, - { label: 'American Beauty', year: 1999 }, - { label: 'The Dark Knight Rises', year: 2012 }, - { label: 'Princess Mononoke', year: 1997 }, - { label: 'Aliens', year: 1986 }, - { label: 'Oldboy', year: 2003 }, - { label: 'Once Upon a Time in America', year: 1984 }, - { label: 'Witness for the Prosecution', year: 1957 }, - { label: 'Das Boot', year: 1981 }, - { label: 'Citizen Kane', year: 1941 }, - { label: 'North by Northwest', year: 1959 }, - { label: 'Vertigo', year: 1958 }, - { - label: 'Star Wars: Episode VI - Return of the Jedi', - year: 1983, - }, - { label: 'Reservoir Dogs', year: 1992 }, - { label: 'Braveheart', year: 1995 }, - { label: 'M', year: 1931 }, - { label: 'Requiem for a Dream', year: 2000 }, - { label: 'Amélie', year: 2001 }, - { label: 'A Clockwork Orange', year: 1971 }, - { label: 'Like Stars on Earth', year: 2007 }, - { label: 'Taxi Driver', year: 1976 }, - { label: 'Lawrence of Arabia', year: 1962 }, - { label: 'Double Indemnity', year: 1944 }, - { - label: 'Eternal Sunshine of the Spotless Mind', - year: 2004, - }, - { label: 'Amadeus', year: 1984 }, - { label: 'To Kill a Mockingbird', year: 1962 }, - { label: 'Toy Story 3', year: 2010 }, - { label: 'Logan', year: 2017 }, - { label: 'Full Metal Jacket', year: 1987 }, - { label: 'Dangal', year: 2016 }, - { label: 'The Sting', year: 1973 }, - { label: '2001: A Space Odyssey', year: 1968 }, - { label: "Singin' in the Rain", year: 1952 }, - { label: 'Toy Story', year: 1995 }, - { label: 'Bicycle Thieves', year: 1948 }, - { label: 'The Kid', year: 1921 }, - { label: 'Inglourious Basterds', year: 2009 }, - { label: 'Snatch', year: 2000 }, - { label: '3 Idiots', year: 2009 }, - { label: 'Monty Python and the Holy Grail', year: 1975 }, -]; diff --git a/docs/data/material/components/autocomplete/top100Films.js b/docs/data/material/components/autocomplete/top100Films.js new file mode 100644 index 00000000000000..3226dcbc8ba7f3 --- /dev/null +++ b/docs/data/material/components/autocomplete/top100Films.js @@ -0,0 +1,129 @@ +// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top +const top100Films = [ + { label: 'The Shawshank Redemption', year: 1994 }, + { label: 'The Godfather', year: 1972 }, + { label: 'The Godfather: Part II', year: 1974 }, + { label: 'The Dark Knight', year: 2008 }, + { label: '12 Angry Men', year: 1957 }, + { label: "Schindler's List", year: 1993 }, + { label: 'Pulp Fiction', year: 1994 }, + { + label: 'The Lord of the Rings: The Return of the King', + year: 2003, + }, + { label: 'The Good, the Bad and the Ugly', year: 1966 }, + { label: 'Fight Club', year: 1999 }, + { + label: 'The Lord of the Rings: The Fellowship of the Ring', + year: 2001, + }, + { + label: 'Star Wars: Episode V - The Empire Strikes Back', + year: 1980, + }, + { label: 'Forrest Gump', year: 1994 }, + { label: 'Inception', year: 2010 }, + { + label: 'The Lord of the Rings: The Two Towers', + year: 2002, + }, + { label: "One Flew Over the Cuckoo's Nest", year: 1975 }, + { label: 'Goodfellas', year: 1990 }, + { label: 'The Matrix', year: 1999 }, + { label: 'Seven Samurai', year: 1954 }, + { + label: 'Star Wars: Episode IV - A New Hope', + year: 1977, + }, + { label: 'City of God', year: 2002 }, + { label: 'Se7en', year: 1995 }, + { label: 'The Silence of the Lambs', year: 1991 }, + { label: "It's a Wonderful Life", year: 1946 }, + { label: 'Life Is Beautiful', year: 1997 }, + { label: 'The Usual Suspects', year: 1995 }, + { label: 'Léon: The Professional', year: 1994 }, + { label: 'Spirited Away', year: 2001 }, + { label: 'Saving Private Ryan', year: 1998 }, + { label: 'Once Upon a Time in the West', year: 1968 }, + { label: 'American History X', year: 1998 }, + { label: 'Interstellar', year: 2014 }, + { label: 'Casablanca', year: 1942 }, + { label: 'City Lights', year: 1931 }, + { label: 'Psycho', year: 1960 }, + { label: 'The Green Mile', year: 1999 }, + { label: 'The Intouchables', year: 2011 }, + { label: 'Modern Times', year: 1936 }, + { label: 'Raiders of the Lost Ark', year: 1981 }, + { label: 'Rear Window', year: 1954 }, + { label: 'The Pianist', year: 2002 }, + { label: 'The Departed', year: 2006 }, + { label: 'Terminator 2: Judgment Day', year: 1991 }, + { label: 'Back to the Future', year: 1985 }, + { label: 'Whiplash', year: 2014 }, + { label: 'Gladiator', year: 2000 }, + { label: 'Memento', year: 2000 }, + { label: 'The Prestige', year: 2006 }, + { label: 'The Lion King', year: 1994 }, + { label: 'Apocalypse Now', year: 1979 }, + { label: 'Alien', year: 1979 }, + { label: 'Sunset Boulevard', year: 1950 }, + { + label: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', + year: 1964, + }, + { label: 'The Great Dictator', year: 1940 }, + { label: 'Cinema Paradiso', year: 1988 }, + { label: 'The Lives of Others', year: 2006 }, + { label: 'Grave of the Fireflies', year: 1988 }, + { label: 'Paths of Glory', year: 1957 }, + { label: 'Django Unchained', year: 2012 }, + { label: 'The Shining', year: 1980 }, + { label: 'WALL·E', year: 2008 }, + { label: 'American Beauty', year: 1999 }, + { label: 'The Dark Knight Rises', year: 2012 }, + { label: 'Princess Mononoke', year: 1997 }, + { label: 'Aliens', year: 1986 }, + { label: 'Oldboy', year: 2003 }, + { label: 'Once Upon a Time in America', year: 1984 }, + { label: 'Witness for the Prosecution', year: 1957 }, + { label: 'Das Boot', year: 1981 }, + { label: 'Citizen Kane', year: 1941 }, + { label: 'North by Northwest', year: 1959 }, + { label: 'Vertigo', year: 1958 }, + { + label: 'Star Wars: Episode VI - Return of the Jedi', + year: 1983, + }, + { label: 'Reservoir Dogs', year: 1992 }, + { label: 'Braveheart', year: 1995 }, + { label: 'M', year: 1931 }, + { label: 'Requiem for a Dream', year: 2000 }, + { label: 'Amélie', year: 2001 }, + { label: 'A Clockwork Orange', year: 1971 }, + { label: 'Like Stars on Earth', year: 2007 }, + { label: 'Taxi Driver', year: 1976 }, + { label: 'Lawrence of Arabia', year: 1962 }, + { label: 'Double Indemnity', year: 1944 }, + { + label: 'Eternal Sunshine of the Spotless Mind', + year: 2004, + }, + { label: 'Amadeus', year: 1984 }, + { label: 'To Kill a Mockingbird', year: 1962 }, + { label: 'Toy Story 3', year: 2010 }, + { label: 'Logan', year: 2017 }, + { label: 'Full Metal Jacket', year: 1987 }, + { label: 'Dangal', year: 2016 }, + { label: 'The Sting', year: 1973 }, + { label: '2001: A Space Odyssey', year: 1968 }, + { label: "Singin' in the Rain", year: 1952 }, + { label: 'Toy Story', year: 1995 }, + { label: 'Bicycle Thieves', year: 1948 }, + { label: 'The Kid', year: 1921 }, + { label: 'Inglourious Basterds', year: 2009 }, + { label: 'Snatch', year: 2000 }, + { label: '3 Idiots', year: 2009 }, + { label: 'Monty Python and the Holy Grail', year: 1975 }, +]; + +export default top100Films; diff --git a/docs/data/material/components/badges/BadgeAlignment.js b/docs/data/material/components/badges/BadgeAlignment.js index 1cce1c8ec7005a..f83681e740c61f 100644 --- a/docs/data/material/components/badges/BadgeAlignment.js +++ b/docs/data/material/components/badges/BadgeAlignment.js @@ -7,7 +7,7 @@ import Radio from '@mui/material/Radio'; import RadioGroup from '@mui/material/RadioGroup'; import Box from '@mui/material/Box'; import MailIcon from '@mui/icons-material/Mail'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; export default function BadgeAlignment() { const [horizontal, setHorizontal] = React.useState('right'); diff --git a/docs/data/material/components/chips/ChipsPlayground.js b/docs/data/material/components/chips/ChipsPlayground.js index fdcc7d5c36d2cd..e7802bb5eaaf8d 100644 --- a/docs/data/material/components/chips/ChipsPlayground.js +++ b/docs/data/material/components/chips/ChipsPlayground.js @@ -9,7 +9,7 @@ import Avatar from '@mui/material/Avatar'; import Chip from '@mui/material/Chip'; import FaceIcon from '@mui/icons-material/Face'; import DoneIcon from '@mui/icons-material/Done'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; function ChipsPlayground() { const [state, setState] = React.useState({ diff --git a/docs/data/material/components/floating-action-button/FloatingActionButtonZoom.js b/docs/data/material/components/floating-action-button/FloatingActionButtonZoom.js index e4945c497d8d87..c8313b1319066e 100644 --- a/docs/data/material/components/floating-action-button/FloatingActionButtonZoom.js +++ b/docs/data/material/components/floating-action-button/FloatingActionButtonZoom.js @@ -1,6 +1,5 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import SwipeableViews from 'react-swipeable-views'; import { useTheme } from '@mui/material/styles'; import AppBar from '@mui/material/AppBar'; import Tabs from '@mui/material/Tabs'; @@ -66,10 +65,6 @@ export default function FloatingActionButtonZoom() { setValue(newValue); }; - const handleChangeIndex = (index) => { - setValue(index); - }; - const transitionDuration = { enter: theme.transitions.duration.enteringScreen, exit: theme.transitions.duration.leavingScreen, @@ -119,21 +114,15 @@ export default function FloatingActionButtonZoom() { - - - Item One - - - Item Two - - - Item Three - - + + Item One + + + Item Two + + + Item Three + {fabs.map((fab, index) => ( { - setValue(index); - }; - const transitionDuration = { enter: theme.transitions.duration.enteringScreen, exit: theme.transitions.duration.leavingScreen, @@ -120,21 +115,15 @@ export default function FloatingActionButtonZoom() { - - - Item One - - - Item Two - - - Item Three - - + + Item One + + + Item Two + + + Item Three + {fabs.map((fab, index) => ( prop !== 'arrow', diff --git a/docs/data/material/components/stack/InteractiveStack.js b/docs/data/material/components/stack/InteractiveStack.js index 8c61706ef15893..270c7d2354c96d 100644 --- a/docs/data/material/components/stack/InteractiveStack.js +++ b/docs/data/material/components/stack/InteractiveStack.js @@ -7,7 +7,7 @@ import Paper from '@mui/material/Paper'; import RadioGroup from '@mui/material/RadioGroup'; import Radio from '@mui/material/Radio'; import Stack from '@mui/material/Stack'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; export default function InteractiveStack() { const [direction, setDirection] = React.useState('row'); diff --git a/docs/data/material/components/stack/InteractiveStack.tsx b/docs/data/material/components/stack/InteractiveStack.tsx index c6320ecb8a77c5..2c4fb30f5c44e8 100644 --- a/docs/data/material/components/stack/InteractiveStack.tsx +++ b/docs/data/material/components/stack/InteractiveStack.tsx @@ -7,7 +7,7 @@ import Paper from '@mui/material/Paper'; import RadioGroup from '@mui/material/RadioGroup'; import Radio from '@mui/material/Radio'; import Stack, { StackProps } from '@mui/material/Stack'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; export default function InteractiveStack() { const [direction, setDirection] = React.useState('row'); diff --git a/docs/data/material/components/steppers/SwipeableTextMobileStepper.js b/docs/data/material/components/steppers/SwipeableTextMobileStepper.js deleted file mode 100644 index d7fd286fadf318..00000000000000 --- a/docs/data/material/components/steppers/SwipeableTextMobileStepper.js +++ /dev/null @@ -1,128 +0,0 @@ -import * as React from 'react'; -import { useTheme } from '@mui/material/styles'; -import Box from '@mui/material/Box'; -import MobileStepper from '@mui/material/MobileStepper'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Button from '@mui/material/Button'; -import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft'; -import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight'; -import SwipeableViews from 'react-swipeable-views'; -import { autoPlay } from 'react-swipeable-views-utils'; - -const AutoPlaySwipeableViews = autoPlay(SwipeableViews); - -const images = [ - { - label: 'San Francisco – Oakland Bay Bridge, United States', - imgPath: - 'https://images.unsplash.com/photo-1537944434965-cf4679d1a598?auto=format&fit=crop&w=400&h=250&q=60', - }, - { - label: 'Bird', - imgPath: - 'https://images.unsplash.com/photo-1538032746644-0212e812a9e7?auto=format&fit=crop&w=400&h=250&q=60', - }, - { - label: 'Bali, Indonesia', - imgPath: - 'https://images.unsplash.com/photo-1537996194471-e657df975ab4?auto=format&fit=crop&w=400&h=250', - }, - { - label: 'Goč, Serbia', - imgPath: - 'https://images.unsplash.com/photo-1512341689857-198e7e2f3ca8?auto=format&fit=crop&w=400&h=250&q=60', - }, -]; - -function SwipeableTextMobileStepper() { - const theme = useTheme(); - const [activeStep, setActiveStep] = React.useState(0); - const maxSteps = images.length; - - const handleNext = () => { - setActiveStep((prevActiveStep) => prevActiveStep + 1); - }; - - const handleBack = () => { - setActiveStep((prevActiveStep) => prevActiveStep - 1); - }; - - const handleStepChange = (step) => { - setActiveStep(step); - }; - - return ( - - - {images[activeStep].label} - - - {images.map((step, index) => ( -
- {Math.abs(activeStep - index) <= 2 ? ( - - ) : null} -
- ))} -
- - Next - {theme.direction === 'rtl' ? ( - - ) : ( - - )} - - } - backButton={ - - } - /> -
- ); -} - -export default SwipeableTextMobileStepper; diff --git a/docs/data/material/components/steppers/SwipeableTextMobileStepper.tsx b/docs/data/material/components/steppers/SwipeableTextMobileStepper.tsx deleted file mode 100644 index 7eb9ecd57e5960..00000000000000 --- a/docs/data/material/components/steppers/SwipeableTextMobileStepper.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import * as React from 'react'; -import { useTheme } from '@mui/material/styles'; -import Box from '@mui/material/Box'; -import MobileStepper from '@mui/material/MobileStepper'; -import Paper from '@mui/material/Paper'; -import Typography from '@mui/material/Typography'; -import Button from '@mui/material/Button'; -import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft'; -import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight'; -import SwipeableViews from 'react-swipeable-views'; -import { autoPlay } from 'react-swipeable-views-utils'; - -const AutoPlaySwipeableViews = autoPlay(SwipeableViews); - -const images = [ - { - label: 'San Francisco – Oakland Bay Bridge, United States', - imgPath: - 'https://images.unsplash.com/photo-1537944434965-cf4679d1a598?auto=format&fit=crop&w=400&h=250&q=60', - }, - { - label: 'Bird', - imgPath: - 'https://images.unsplash.com/photo-1538032746644-0212e812a9e7?auto=format&fit=crop&w=400&h=250&q=60', - }, - { - label: 'Bali, Indonesia', - imgPath: - 'https://images.unsplash.com/photo-1537996194471-e657df975ab4?auto=format&fit=crop&w=400&h=250', - }, - { - label: 'Goč, Serbia', - imgPath: - 'https://images.unsplash.com/photo-1512341689857-198e7e2f3ca8?auto=format&fit=crop&w=400&h=250&q=60', - }, -]; - -function SwipeableTextMobileStepper() { - const theme = useTheme(); - const [activeStep, setActiveStep] = React.useState(0); - const maxSteps = images.length; - - const handleNext = () => { - setActiveStep((prevActiveStep) => prevActiveStep + 1); - }; - - const handleBack = () => { - setActiveStep((prevActiveStep) => prevActiveStep - 1); - }; - - const handleStepChange = (step: number) => { - setActiveStep(step); - }; - - return ( - - - {images[activeStep].label} - - - {images.map((step, index) => ( -
- {Math.abs(activeStep - index) <= 2 ? ( - - ) : null} -
- ))} -
- - Next - {theme.direction === 'rtl' ? ( - - ) : ( - - )} - - } - backButton={ - - } - /> -
- ); -} - -export default SwipeableTextMobileStepper; diff --git a/docs/data/material/components/steppers/steppers.md b/docs/data/material/components/steppers/steppers.md index 909ed00bd884f3..8b8181d6db1497 100644 --- a/docs/data/material/components/steppers/steppers.md +++ b/docs/data/material/components/steppers/steppers.md @@ -94,13 +94,6 @@ The current step and total number of steps are displayed as text. {{"demo": "TextMobileStepper.js", "bg": true}} -### Text with carousel effect - -This demo uses -[react-swipeable-views](https://github.com/oliviertassinari/react-swipeable-views) to create a carousel. - -{{"demo": "SwipeableTextMobileStepper.js", "bg": true}} - ### Dots Use dots when the number of steps is small. diff --git a/docs/data/material/components/table/EnhancedTable.js b/docs/data/material/components/table/EnhancedTable.js index 8417fa180abbe7..b0fa5ea53be9ce 100644 --- a/docs/data/material/components/table/EnhancedTable.js +++ b/docs/data/material/components/table/EnhancedTable.js @@ -65,22 +65,6 @@ function getComparator(order, orderBy) { : (a, b) => -descendingComparator(a, b, orderBy); } -// Since 2020 all major browsers ensure sort stability with Array.prototype.sort(). -// stableSort() brings sort stability to non-modern browsers (notably IE11). If you -// only support modern browsers you can replace stableSort(exampleArray, exampleComparator) -// with exampleArray.slice().sort(exampleComparator) -function stableSort(array, comparator) { - const stabilizedThis = array.map((el, index) => [el, index]); - stabilizedThis.sort((a, b) => { - const order = comparator(a[0], b[0]); - if (order !== 0) { - return order; - } - return a[1] - b[1]; - }); - return stabilizedThis.map((el) => el[0]); -} - const headCells = [ { id: 'name', @@ -288,10 +272,9 @@ export default function EnhancedTable() { const visibleRows = React.useMemo( () => - stableSort(rows, getComparator(order, orderBy)).slice( - page * rowsPerPage, - page * rowsPerPage + rowsPerPage, - ), + [...rows] + .sort(getComparator(order, orderBy)) + .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage), [order, orderBy, page, rowsPerPage], ); diff --git a/docs/data/material/components/table/EnhancedTable.tsx b/docs/data/material/components/table/EnhancedTable.tsx index d1fd663dc821cc..23d1f23a1c19d2 100644 --- a/docs/data/material/components/table/EnhancedTable.tsx +++ b/docs/data/material/components/table/EnhancedTable.tsx @@ -88,22 +88,6 @@ function getComparator( : (a, b) => -descendingComparator(a, b, orderBy); } -// Since 2020 all major browsers ensure sort stability with Array.prototype.sort(). -// stableSort() brings sort stability to non-modern browsers (notably IE11). If you -// only support modern browsers you can replace stableSort(exampleArray, exampleComparator) -// with exampleArray.slice().sort(exampleComparator) -function stableSort(array: readonly T[], comparator: (a: T, b: T) => number) { - const stabilizedThis = array.map((el, index) => [el, index] as [T, number]); - stabilizedThis.sort((a, b) => { - const order = comparator(a[0], b[0]); - if (order !== 0) { - return order; - } - return a[1] - b[1]; - }); - return stabilizedThis.map((el) => el[0]); -} - interface HeadCell { disablePadding: boolean; id: keyof Data; @@ -320,10 +304,9 @@ export default function EnhancedTable() { const visibleRows = React.useMemo( () => - stableSort(rows, getComparator(order, orderBy)).slice( - page * rowsPerPage, - page * rowsPerPage + rowsPerPage, - ), + [...rows] + .sort(getComparator(order, orderBy)) + .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage), [order, orderBy, page, rowsPerPage], ); diff --git a/docs/data/material/components/tabs/FullWidthTabs.js b/docs/data/material/components/tabs/FullWidthTabs.js index 8439038ffc54b5..2e8a08deba0e8a 100644 --- a/docs/data/material/components/tabs/FullWidthTabs.js +++ b/docs/data/material/components/tabs/FullWidthTabs.js @@ -1,6 +1,5 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import SwipeableViews from 'react-swipeable-views'; import { useTheme } from '@mui/material/styles'; import AppBar from '@mui/material/AppBar'; import Tabs from '@mui/material/Tabs'; @@ -49,10 +48,6 @@ export default function FullWidthTabs() { setValue(newValue); }; - const handleChangeIndex = (index) => { - setValue(index); - }; - return ( @@ -69,21 +64,15 @@ export default function FullWidthTabs() { - - - Item One - - - Item Two - - - Item Three - - + + Item One + + + Item Two + + + Item Three + ); } diff --git a/docs/data/material/components/tabs/FullWidthTabs.tsx b/docs/data/material/components/tabs/FullWidthTabs.tsx index 0b3b1c34d556cf..99ff253bb02f63 100644 --- a/docs/data/material/components/tabs/FullWidthTabs.tsx +++ b/docs/data/material/components/tabs/FullWidthTabs.tsx @@ -1,5 +1,4 @@ import * as React from 'react'; -import SwipeableViews from 'react-swipeable-views'; import { useTheme } from '@mui/material/styles'; import AppBar from '@mui/material/AppBar'; import Tabs from '@mui/material/Tabs'; @@ -49,10 +48,6 @@ export default function FullWidthTabs() { setValue(newValue); }; - const handleChangeIndex = (index: number) => { - setValue(index); - }; - return ( @@ -69,21 +64,15 @@ export default function FullWidthTabs() { - - - Item One - - - Item Two - - - Item Three - - + + Item One + + + Item Two + + + Item Three + ); } diff --git a/docs/data/material/components/tabs/tabs.md b/docs/data/material/components/tabs/tabs.md index f75936d72dee57..443e2daf8cda99 100644 --- a/docs/data/material/components/tabs/tabs.md +++ b/docs/data/material/components/tabs/tabs.md @@ -67,7 +67,6 @@ Fixed tabs should be used with a limited number of tabs, and when a consistent p ### Full width The `variant="fullWidth"` prop should be used for smaller views. -This demo also uses [react-swipeable-views](https://github.com/oliviertassinari/react-swipeable-views) to animate the Tab transition, and allowing tabs to be swiped on touch devices. {{"demo": "FullWidthTabs.js", "bg": true}} diff --git a/docs/data/material/getting-started/templates/checkout/Checkout.js b/docs/data/material/getting-started/templates/checkout/Checkout.js index d0929cac54591d..32e9da0dc52420 100644 --- a/docs/data/material/getting-started/templates/checkout/Checkout.js +++ b/docs/data/material/getting-started/templates/checkout/Checkout.js @@ -142,7 +142,7 @@ export default function Checkout() { - @@ -190,26 +176,12 @@ function AppAppBar({ mode, toggleColorMode }) { scrollToSection('faq')}>FAQ - - diff --git a/docs/data/material/getting-started/templates/landing-page/components/AppAppBar.tsx b/docs/data/material/getting-started/templates/landing-page/components/AppAppBar.tsx index d0b2a9b6e99a98..5402d2072c46b1 100644 --- a/docs/data/material/getting-started/templates/landing-page/components/AppAppBar.tsx +++ b/docs/data/material/getting-started/templates/landing-page/components/AppAppBar.tsx @@ -135,24 +135,10 @@ export default function AppAppBar({ mode, toggleColorMode }: AppAppBarProps) { }} > - - @@ -194,26 +180,12 @@ export default function AppAppBar({ mode, toggleColorMode }: AppAppBarProps) { scrollToSection('faq')}>FAQ - - diff --git a/docs/data/material/getting-started/templates/landing-page/components/Features.js b/docs/data/material/getting-started/templates/landing-page/components/Features.js index 565084d9b210a9..34b8842a6a8539 100644 --- a/docs/data/material/getting-started/templates/landing-page/components/Features.js +++ b/docs/data/material/getting-started/templates/landing-page/components/Features.js @@ -2,12 +2,15 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import Card from '@mui/material/Card'; -import Chip from '@mui/material/Chip'; +import { Chip as MuiChip } from '@mui/material'; import Container from '@mui/material/Container'; import Grid from '@mui/material/Grid'; import Link from '@mui/material/Link'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; + +import { styled } from '@mui/material/styles'; + import ChevronRightRoundedIcon from '@mui/icons-material/ChevronRightRounded'; import DevicesRoundedIcon from '@mui/icons-material/DevicesRounded'; import EdgesensorHighRoundedIcon from '@mui/icons-material/EdgesensorHighRounded'; @@ -40,6 +43,21 @@ const items = [ }, ]; +const Chip = styled(MuiChip)(({ theme, selected }) => ({ + ...(selected && { + borderColor: + theme.palette.mode === 'light' + ? theme.palette.primary.light + : theme.palette.primary.dark, + background: + 'linear-gradient(to bottom right, hsl(210, 98%, 48%), hsl(210, 98%, 35%))', + color: 'hsl(0, 0%, 100%)', + '& .MuiChip-label': { + color: 'hsl(0, 0%, 100%)', + }, + }), +})); + export default function Features() { const [selectedItemIndex, setSelectedItemIndex] = React.useState(0); @@ -73,20 +91,7 @@ export default function Features() { key={index} label={title} onClick={() => handleItemClick(index)} - sx={(theme) => ({ - ...(selectedItemIndex === index && { - borderColor: - theme.palette.mode === 'light' - ? 'primary.light' - : 'primary.dark', - background: - 'linear-gradient(to bottom right, hsl(210, 98%, 48%), hsl(210, 98%, 35%))', - color: 'hsl(0, 0%, 100%)', - '& .MuiChip-label': { - color: 'hsl(0, 0%, 100%)', - }, - }), - })} + selected={selectedItemIndex === index} /> ))} diff --git a/docs/data/material/getting-started/templates/landing-page/components/Features.tsx b/docs/data/material/getting-started/templates/landing-page/components/Features.tsx index f02afaa5483979..1f198bafe9b841 100644 --- a/docs/data/material/getting-started/templates/landing-page/components/Features.tsx +++ b/docs/data/material/getting-started/templates/landing-page/components/Features.tsx @@ -2,12 +2,15 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import Card from '@mui/material/Card'; -import Chip from '@mui/material/Chip'; +import { Chip as MuiChip } from '@mui/material'; import Container from '@mui/material/Container'; import Grid from '@mui/material/Grid'; import Link from '@mui/material/Link'; import Stack from '@mui/material/Stack'; import Typography from '@mui/material/Typography'; + +import { styled } from '@mui/material/styles'; + import ChevronRightRoundedIcon from '@mui/icons-material/ChevronRightRounded'; import DevicesRoundedIcon from '@mui/icons-material/DevicesRounded'; import EdgesensorHighRoundedIcon from '@mui/icons-material/EdgesensorHighRounded'; @@ -40,6 +43,25 @@ const items = [ }, ]; +interface ChipProps { + selected?: boolean; +} + +const Chip = styled(MuiChip)(({ theme, selected }) => ({ + ...(selected && { + borderColor: + theme.palette.mode === 'light' + ? theme.palette.primary.light + : theme.palette.primary.dark, + background: + 'linear-gradient(to bottom right, hsl(210, 98%, 48%), hsl(210, 98%, 35%))', + color: 'hsl(0, 0%, 100%)', + '& .MuiChip-label': { + color: 'hsl(0, 0%, 100%)', + }, + }), +})); + export default function Features() { const [selectedItemIndex, setSelectedItemIndex] = React.useState(0); @@ -73,20 +95,7 @@ export default function Features() { key={index} label={title} onClick={() => handleItemClick(index)} - sx={(theme) => ({ - ...(selectedItemIndex === index && { - borderColor: - theme.palette.mode === 'light' - ? 'primary.light' - : 'primary.dark', - background: - 'linear-gradient(to bottom right, hsl(210, 98%, 48%), hsl(210, 98%, 35%))', - color: 'hsl(0, 0%, 100%)', - '& .MuiChip-label': { - color: 'hsl(0, 0%, 100%)', - }, - }), - })} + selected={selectedItemIndex === index} /> ))} diff --git a/docs/data/material/getting-started/templates/landing-page/components/Hero.js b/docs/data/material/getting-started/templates/landing-page/components/Hero.js index a8e9b21b0c2ef9..dadc3e27009461 100644 --- a/docs/data/material/getting-started/templates/landing-page/components/Hero.js +++ b/docs/data/material/getting-started/templates/landing-page/components/Hero.js @@ -9,6 +9,34 @@ import TextField from '@mui/material/TextField'; import Typography from '@mui/material/Typography'; import { visuallyHidden } from '@mui/utils'; +import { styled } from '@mui/material/styles'; + +const StyledBox = styled('div')(({ theme }) => ({ + alignSelf: 'center', + width: '100%', + height: 400, + marginTop: theme.spacing(8), + borderRadius: theme.shape.borderRadius, + boxShadow: + theme.palette.mode === 'light' + ? '0 0 12px 8px hsla(220, 25%, 80%, 0.2)' + : '0 0 24px 12px hsla(210, 100%, 25%, 0.2)', + outline: '1px solid', + backgroundImage: `url(${ + theme.palette.mode === 'light' + ? '/static/images/templates/templates-images/hero-light.png' + : '/static/images/templates/templates-images/hero-dark.png' + })`, + backgroundSize: 'cover', + outlineColor: + theme.palette.mode === 'light' + ? 'hsla(220, 25%, 80%, 0.5)' + : 'hsla(210, 100%, 80%, 0.1)', + [theme.breakpoints.up('sm')]: { + marginTop: theme.spacing(10), + height: 700, + }, +})); export default function Hero() { return ( @@ -102,30 +130,7 @@ export default function Hero() { . - ({ - mt: { xs: 8, sm: 10 }, - alignSelf: 'center', - height: { xs: 200, sm: 700 }, - width: '100%', - backgroundImage: - theme.palette.mode === 'light' - ? 'url("/static/images/templates/templates-images/hero-light.png")' - : 'url("/static/images/templates/templates-images/hero-dark.png")', - backgroundSize: 'cover', - borderRadius: '12px', - outline: '1px solid', - outlineColor: - theme.palette.mode === 'light' - ? 'hsla(220, 25%, 80%, 0.5)' - : 'hsla(210, 100%, 80%, 0.1)', - boxShadow: - theme.palette.mode === 'light' - ? '0 0 12px 8px hsla(220, 25%, 80%, 0.2)' - : '0 0 24px 12px hsla(210, 100%, 25%, 0.2)', - })} - /> + ); diff --git a/docs/data/material/getting-started/templates/landing-page/components/Hero.tsx b/docs/data/material/getting-started/templates/landing-page/components/Hero.tsx index a8e9b21b0c2ef9..dadc3e27009461 100644 --- a/docs/data/material/getting-started/templates/landing-page/components/Hero.tsx +++ b/docs/data/material/getting-started/templates/landing-page/components/Hero.tsx @@ -9,6 +9,34 @@ import TextField from '@mui/material/TextField'; import Typography from '@mui/material/Typography'; import { visuallyHidden } from '@mui/utils'; +import { styled } from '@mui/material/styles'; + +const StyledBox = styled('div')(({ theme }) => ({ + alignSelf: 'center', + width: '100%', + height: 400, + marginTop: theme.spacing(8), + borderRadius: theme.shape.borderRadius, + boxShadow: + theme.palette.mode === 'light' + ? '0 0 12px 8px hsla(220, 25%, 80%, 0.2)' + : '0 0 24px 12px hsla(210, 100%, 25%, 0.2)', + outline: '1px solid', + backgroundImage: `url(${ + theme.palette.mode === 'light' + ? '/static/images/templates/templates-images/hero-light.png' + : '/static/images/templates/templates-images/hero-dark.png' + })`, + backgroundSize: 'cover', + outlineColor: + theme.palette.mode === 'light' + ? 'hsla(220, 25%, 80%, 0.5)' + : 'hsla(210, 100%, 80%, 0.1)', + [theme.breakpoints.up('sm')]: { + marginTop: theme.spacing(10), + height: 700, + }, +})); export default function Hero() { return ( @@ -102,30 +130,7 @@ export default function Hero() { . - ({ - mt: { xs: 8, sm: 10 }, - alignSelf: 'center', - height: { xs: 200, sm: 700 }, - width: '100%', - backgroundImage: - theme.palette.mode === 'light' - ? 'url("/static/images/templates/templates-images/hero-light.png")' - : 'url("/static/images/templates/templates-images/hero-dark.png")', - backgroundSize: 'cover', - borderRadius: '12px', - outline: '1px solid', - outlineColor: - theme.palette.mode === 'light' - ? 'hsla(220, 25%, 80%, 0.5)' - : 'hsla(210, 100%, 80%, 0.1)', - boxShadow: - theme.palette.mode === 'light' - ? '0 0 12px 8px hsla(220, 25%, 80%, 0.2)' - : '0 0 24px 12px hsla(210, 100%, 25%, 0.2)', - })} - /> + ); diff --git a/docs/data/material/getting-started/templates/landing-page/components/Pricing.js b/docs/data/material/getting-started/templates/landing-page/components/Pricing.js index 54a00b4a03dcd8..5a005b5f68e74b 100644 --- a/docs/data/material/getting-started/templates/landing-page/components/Pricing.js +++ b/docs/data/material/getting-started/templates/landing-page/components/Pricing.js @@ -196,13 +196,7 @@ export default function Pricing() { ))} - diff --git a/docs/data/material/getting-started/templates/landing-page/components/Pricing.tsx b/docs/data/material/getting-started/templates/landing-page/components/Pricing.tsx index 52ca695ee1ff1e..5c508931a71af3 100644 --- a/docs/data/material/getting-started/templates/landing-page/components/Pricing.tsx +++ b/docs/data/material/getting-started/templates/landing-page/components/Pricing.tsx @@ -199,9 +199,6 @@ export default function Pricing() { diff --git a/docs/data/material/getting-started/templates/sign-in-side/SignInCard.js b/docs/data/material/getting-started/templates/sign-in-side/SignInCard.js index 9c6c23678ee7b9..92d27a719c33fb 100644 --- a/docs/data/material/getting-started/templates/sign-in-side/SignInCard.js +++ b/docs/data/material/getting-started/templates/sign-in-side/SignInCard.js @@ -1,7 +1,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; -import Card from '@mui/material/Card'; +import { Card as MuiCard } from '@mui/material'; import Checkbox from '@mui/material/Checkbox'; import Divider from '@mui/material/Divider'; import FormLabel from '@mui/material/FormLabel'; @@ -11,9 +11,28 @@ import Link from '@mui/material/Link'; import TextField from '@mui/material/TextField'; import Typography from '@mui/material/Typography'; +import { styled } from '@mui/material/styles'; + import ForgotPassword from './ForgotPassword'; import { GoogleIcon, FacebookIcon, SitemarkIcon } from './CustomIcons'; +const Card = styled(MuiCard)(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + alignSelf: 'center', + gap: theme.spacing(4), + width: '100%', + padding: theme.spacing(2), + boxShadow: + theme.palette.mode === 'light' + ? 'hsla(220, 30%, 5%, 0.05) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.05) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px' + : 'hsla(220, 30%, 5%, 0.5) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.08) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px', + [theme.breakpoints.up('sm')]: { + padding: theme.spacing(4), + width: '450px', + }, +})); + export default function SignInCard() { const [emailError, setEmailError] = React.useState(false); const [emailErrorMessage, setEmailErrorMessage] = React.useState(''); @@ -66,20 +85,7 @@ export default function SignInCard() { }; return ( - ({ - display: 'flex', - flexDirection: 'column', - alignSelf: 'center', - width: { xs: '100%', sm: '450px' }, - p: { xs: 2, sm: 4 }, - gap: 2, - boxShadow: - theme.palette.mode === 'light' - ? 'hsla(220, 30%, 5%, 0.05) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.05) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px' - : 'hsla(220, 30%, 5%, 0.5) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.08) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px', - })} - > + diff --git a/docs/data/material/getting-started/templates/sign-in-side/SignInCard.tsx b/docs/data/material/getting-started/templates/sign-in-side/SignInCard.tsx index 8697dcc3e042df..139b35c8ad4ad7 100644 --- a/docs/data/material/getting-started/templates/sign-in-side/SignInCard.tsx +++ b/docs/data/material/getting-started/templates/sign-in-side/SignInCard.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; -import Card from '@mui/material/Card'; +import { Card as MuiCard } from '@mui/material'; import Checkbox from '@mui/material/Checkbox'; import Divider from '@mui/material/Divider'; import FormLabel from '@mui/material/FormLabel'; @@ -11,9 +11,28 @@ import Link from '@mui/material/Link'; import TextField from '@mui/material/TextField'; import Typography from '@mui/material/Typography'; +import { styled } from '@mui/material/styles'; + import ForgotPassword from './ForgotPassword'; import { GoogleIcon, FacebookIcon, SitemarkIcon } from './CustomIcons'; +const Card = styled(MuiCard)(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + alignSelf: 'center', + gap: theme.spacing(4), + width: '100%', + padding: theme.spacing(2), + boxShadow: + theme.palette.mode === 'light' + ? 'hsla(220, 30%, 5%, 0.05) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.05) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px' + : 'hsla(220, 30%, 5%, 0.5) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.08) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px', + [theme.breakpoints.up('sm')]: { + padding: theme.spacing(4), + width: '450px', + }, +})); + export default function SignInCard() { const [emailError, setEmailError] = React.useState(false); const [emailErrorMessage, setEmailErrorMessage] = React.useState(''); @@ -66,20 +85,7 @@ export default function SignInCard() { }; return ( - ({ - display: 'flex', - flexDirection: 'column', - alignSelf: 'center', - width: { xs: '100%', sm: '450px' }, - p: { xs: 2, sm: 4 }, - gap: 2, - boxShadow: - theme.palette.mode === 'light' - ? 'hsla(220, 30%, 5%, 0.05) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.05) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px' - : 'hsla(220, 30%, 5%, 0.5) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.08) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px', - })} - > + diff --git a/docs/data/material/getting-started/templates/sign-in/SignIn.js b/docs/data/material/getting-started/templates/sign-in/SignIn.js index 8398bfef899d8f..ba53cf3e9ddf2a 100644 --- a/docs/data/material/getting-started/templates/sign-in/SignIn.js +++ b/docs/data/material/getting-started/templates/sign-in/SignIn.js @@ -2,7 +2,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; -import Card from '@mui/material/Card'; import Checkbox from '@mui/material/Checkbox'; import CssBaseline from '@mui/material/CssBaseline'; import FormControlLabel from '@mui/material/FormControlLabel'; @@ -15,8 +14,8 @@ import ToggleButton from '@mui/material/ToggleButton'; import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; import Typography from '@mui/material/Typography'; import Stack from '@mui/material/Stack'; - -import { ThemeProvider, createTheme } from '@mui/material/styles'; +import { Card as MuiCard } from '@mui/material'; +import { ThemeProvider, createTheme, styled } from '@mui/material/styles'; import ArrowBackRoundedIcon from '@mui/icons-material/ArrowBackRounded'; import AutoAwesomeRoundedIcon from '@mui/icons-material/AutoAwesomeRounded'; @@ -68,6 +67,37 @@ ToggleCustomTheme.propTypes = { toggleCustomTheme: PropTypes.func.isRequired, }; +const Card = styled(MuiCard)(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + alignSelf: 'center', + gap: theme.spacing(4), + width: '100%', + padding: theme.spacing(2), + boxShadow: + theme.palette.mode === 'light' + ? 'hsla(220, 30%, 5%, 0.05) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.05) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px' + : 'hsla(220, 30%, 5%, 0.5) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.08) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px', + [theme.breakpoints.up('sm')]: { + padding: theme.spacing(4), + width: '450px', + }, +})); + +const SignInContainer = styled(Stack)(({ theme }) => ({ + height: 'auto', + padingBottom: theme.spacing(12), + backgroundImage: + theme.palette.mode === 'light' + ? 'radial-gradient(ellipse at 50% 50%, hsl(210, 100%, 97%), hsl(0, 0%, 100%))' + : 'radial-gradient(at 50% 50%, hsla(210, 100%, 16%, 0.3), hsl(220, 30%, 5%))', + backgroundRepeat: 'no-repeat', + [theme.breakpoints.up('sm')]: { + paddingBottom: 0, + height: '100dvh', + }, +})); + export default function SignIn() { const [mode, setMode] = React.useState('light'); const [showCustomTheme, setShowCustomTheme] = React.useState(true); @@ -134,20 +164,7 @@ export default function SignIn() { return ( - ({ - backgroundImage: - theme.palette.mode === 'light' - ? 'radial-gradient(ellipse at 50% 50%, hsl(210, 100%, 97%), hsl(0, 0%, 100%))' - : 'radial-gradient(at 50% 50%, hsla(210, 100%, 16%, 0.3), hsl(220, 30%, 5%))', - backgroundRepeat: 'no-repeat', - height: { xs: 'auto', sm: '100dvh' }, - pb: { xs: 12, sm: 0 }, - })} - component="main" - > + - ({ - display: 'flex', - flexDirection: 'column', - alignSelf: 'center', - width: { xs: '100%', sm: '450px' }, - p: { xs: 2, sm: 4 }, - gap: 4, - boxShadow: - theme.palette.mode === 'light' - ? 'hsla(220, 30%, 5%, 0.05) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.05) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px' - : 'hsla(220, 30%, 5%, 0.5) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.08) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px', - })} - > + - + ({ + display: 'flex', + flexDirection: 'column', + alignSelf: 'center', + gap: theme.spacing(4), + width: '100%', + padding: theme.spacing(2), + boxShadow: + theme.palette.mode === 'light' + ? 'hsla(220, 30%, 5%, 0.05) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.05) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px' + : 'hsla(220, 30%, 5%, 0.5) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.08) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px', + [theme.breakpoints.up('sm')]: { + padding: theme.spacing(4), + width: '450px', + }, +})); + +const SignInContainer = styled(Stack)(({ theme }) => ({ + height: 'auto', + padingBottom: theme.spacing(12), + backgroundImage: + theme.palette.mode === 'light' + ? 'radial-gradient(ellipse at 50% 50%, hsl(210, 100%, 97%), hsl(0, 0%, 100%))' + : 'radial-gradient(at 50% 50%, hsla(210, 100%, 16%, 0.3), hsl(220, 30%, 5%))', + backgroundRepeat: 'no-repeat', + [theme.breakpoints.up('sm')]: { + paddingBottom: 0, + height: '100dvh', + }, +})); + export default function SignIn() { const [mode, setMode] = React.useState('light'); const [showCustomTheme, setShowCustomTheme] = React.useState(true); @@ -134,20 +164,7 @@ export default function SignIn() { return ( - ({ - backgroundImage: - theme.palette.mode === 'light' - ? 'radial-gradient(ellipse at 50% 50%, hsl(210, 100%, 97%), hsl(0, 0%, 100%))' - : 'radial-gradient(at 50% 50%, hsla(210, 100%, 16%, 0.3), hsl(220, 30%, 5%))', - backgroundRepeat: 'no-repeat', - height: { xs: 'auto', sm: '100dvh' }, - pb: { xs: 12, sm: 0 }, - })} - component="main" - > + - ({ - display: 'flex', - flexDirection: 'column', - alignSelf: 'center', - width: { xs: '100%', sm: '450px' }, - p: { xs: 2, sm: 4 }, - gap: 4, - boxShadow: - theme.palette.mode === 'light' - ? 'hsla(220, 30%, 5%, 0.05) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.05) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px' - : 'hsla(220, 30%, 5%, 0.5) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.08) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px', - })} - > + - + ({ + display: 'flex', + flexDirection: 'column', + alignSelf: 'center', + gap: theme.spacing(4), + width: '100%', + padding: theme.spacing(2), + boxShadow: + theme.palette.mode === 'light' + ? 'hsla(220, 30%, 5%, 0.05) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.05) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px' + : 'hsla(220, 30%, 5%, 0.5) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.08) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px', + [theme.breakpoints.up('sm')]: { + padding: theme.spacing(4), + width: '450px', + }, +})); + +const SignUpContainer = styled(Stack)(({ theme }) => ({ + height: 'auto', + padingBottom: theme.spacing(12), + backgroundImage: + theme.palette.mode === 'light' + ? 'radial-gradient(ellipse at 50% 50%, hsl(210, 100%, 97%), hsl(0, 0%, 100%))' + : 'radial-gradient(at 50% 50%, hsla(210, 100%, 16%, 0.3), hsl(220, 30%, 5%))', + backgroundRepeat: 'no-repeat', + [theme.breakpoints.up('sm')]: { + paddingBottom: 0, + height: '100dvh', + }, +})); + export default function SignUp() { const [mode, setMode] = React.useState('light'); const [showCustomTheme, setShowCustomTheme] = React.useState(true); @@ -138,19 +168,7 @@ export default function SignUp() { return ( - ({ - backgroundRepeat: 'no-repeat', - backgroundImage: - theme.palette.mode === 'light' - ? 'radial-gradient(ellipse at 50% 50%, hsl(210, 100%, 97%), hsl(0, 0%, 100%))' - : 'radial-gradient(at 50% 50%, hsla(210, 100%, 16%, 0.3), hsl(220, 30%, 5%))', - pb: { xs: 12, sm: 0 }, - })} - > + - ({ - display: 'flex', - flexDirection: 'column', - alignSelf: 'center', - width: { xs: '100%', sm: '450px' }, - p: { xs: 2, sm: 4 }, - gap: 4, - boxShadow: - theme.palette.mode === 'light' - ? 'hsla(220, 30%, 5%, 0.05) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.05) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px' - : 'hsla(220, 30%, 5%, 0.5) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.08) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px', - })} - > + - + ({ + display: 'flex', + flexDirection: 'column', + alignSelf: 'center', + gap: theme.spacing(4), + width: '100%', + padding: theme.spacing(2), + boxShadow: + theme.palette.mode === 'light' + ? 'hsla(220, 30%, 5%, 0.05) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.05) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px' + : 'hsla(220, 30%, 5%, 0.5) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.08) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px', + [theme.breakpoints.up('sm')]: { + padding: theme.spacing(4), + width: '450px', + }, +})); + +const SignUpContainer = styled(Stack)(({ theme }) => ({ + height: 'auto', + padingBottom: theme.spacing(12), + backgroundImage: + theme.palette.mode === 'light' + ? 'radial-gradient(ellipse at 50% 50%, hsl(210, 100%, 97%), hsl(0, 0%, 100%))' + : 'radial-gradient(at 50% 50%, hsla(210, 100%, 16%, 0.3), hsl(220, 30%, 5%))', + backgroundRepeat: 'no-repeat', + [theme.breakpoints.up('sm')]: { + paddingBottom: 0, + height: '100dvh', + }, +})); + export default function SignUp() { const [mode, setMode] = React.useState('light'); const [showCustomTheme, setShowCustomTheme] = React.useState(true); @@ -138,19 +168,7 @@ export default function SignUp() { return ( - ({ - backgroundRepeat: 'no-repeat', - backgroundImage: - theme.palette.mode === 'light' - ? 'radial-gradient(ellipse at 50% 50%, hsl(210, 100%, 97%), hsl(0, 0%, 100%))' - : 'radial-gradient(at 50% 50%, hsla(210, 100%, 16%, 0.3), hsl(220, 30%, 5%))', - pb: { xs: 12, sm: 0 }, - })} - > + - ({ - display: 'flex', - flexDirection: 'column', - alignSelf: 'center', - width: { xs: '100%', sm: '450px' }, - p: { xs: 2, sm: 4 }, - gap: 4, - boxShadow: - theme.palette.mode === 'light' - ? 'hsla(220, 30%, 5%, 0.05) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.05) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px' - : 'hsla(220, 30%, 5%, 0.5) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.08) 0px 15px 35px -5px, hsla(220, 30%, 5%, 0.05) 0px 0px 0px 1px', - })} - > + - + premium template section. -react templates + +The MUI Store includes several carefully curated React templates using Material UI + + +The MUI Store includes several carefully curated React templates using Material UI + diff --git a/docs/data/system/components/grid/SpacingGrid.js b/docs/data/system/components/grid/SpacingGrid.js index 4ffd3591650ef4..79e2db15c03725 100644 --- a/docs/data/system/components/grid/SpacingGrid.js +++ b/docs/data/system/components/grid/SpacingGrid.js @@ -6,7 +6,7 @@ import FormControlLabel from '@mui/material/FormControlLabel'; import RadioGroup from '@mui/material/RadioGroup'; import Radio from '@mui/material/Radio'; import Paper from '@mui/material/Paper'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; export default function SpacingGrid() { const [spacing, setSpacing] = React.useState(2); diff --git a/docs/data/system/components/grid/SpacingGrid.tsx b/docs/data/system/components/grid/SpacingGrid.tsx index 97c0d5fe114b2d..80a78f26c3ca75 100644 --- a/docs/data/system/components/grid/SpacingGrid.tsx +++ b/docs/data/system/components/grid/SpacingGrid.tsx @@ -6,7 +6,7 @@ import FormControlLabel from '@mui/material/FormControlLabel'; import RadioGroup from '@mui/material/RadioGroup'; import Radio from '@mui/material/Radio'; import Paper from '@mui/material/Paper'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; export default function SpacingGrid() { const [spacing, setSpacing] = React.useState(2); diff --git a/docs/data/system/components/stack/InteractiveStack.js b/docs/data/system/components/stack/InteractiveStack.js index 25f978b8fe2827..ed48e6ac727308 100644 --- a/docs/data/system/components/stack/InteractiveStack.js +++ b/docs/data/system/components/stack/InteractiveStack.js @@ -8,7 +8,7 @@ import Radio from '@mui/material/Radio'; import Grid from '@mui/system/Unstable_Grid'; import Stack from '@mui/system/Stack'; import { styled } from '@mui/system'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; const Item = styled('div')(({ theme }) => ({ backgroundColor: theme.palette.mode === 'dark' ? '#262B32' : '#fff', diff --git a/docs/data/system/components/stack/InteractiveStack.tsx b/docs/data/system/components/stack/InteractiveStack.tsx index 026d18c5ff7d5f..40c09e895eddc1 100644 --- a/docs/data/system/components/stack/InteractiveStack.tsx +++ b/docs/data/system/components/stack/InteractiveStack.tsx @@ -8,7 +8,7 @@ import Radio from '@mui/material/Radio'; import Grid from '@mui/system/Unstable_Grid'; import Stack, { StackProps } from '@mui/system/Stack'; import { styled } from '@mui/system'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; const Item = styled('div')(({ theme }) => ({ backgroundColor: theme.palette.mode === 'dark' ? '#262B32' : '#fff', diff --git a/docs/data/system/getting-started/the-sx-prop/the-sx-prop.md b/docs/data/system/getting-started/the-sx-prop/the-sx-prop.md index a3e75054c37355..17b147787e83b6 100644 --- a/docs/data/system/getting-started/the-sx-prop/the-sx-prop.md +++ b/docs/data/system/getting-started/the-sx-prop/the-sx-prop.md @@ -179,7 +179,7 @@ Read more on the [Typography page](/system/typography/). ## Responsive values -All properties associated with the `sx` prop also support responsive values for specific breakpoints. +All properties associated with the `sx` prop also support responsive values for specific breakpoints and container queries. Read more on the [Usage page—Responsive values](/system/getting-started/usage/#responsive-values). diff --git a/docs/data/system/getting-started/usage/ContainerQueries.js b/docs/data/system/getting-started/usage/ContainerQueries.js new file mode 100644 index 00000000000000..aa1e523a0989e4 --- /dev/null +++ b/docs/data/system/getting-started/usage/ContainerQueries.js @@ -0,0 +1,88 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; + +export default function ContainerQueries() { + return ( + + + + +
+ + 123 Main St, Phoenix AZ + + + $280,000 — $310,000 + +
+ + Confidence score: 85% + +
+
+
+ ); +} diff --git a/docs/data/system/getting-started/usage/ContainerQueries.tsx b/docs/data/system/getting-started/usage/ContainerQueries.tsx new file mode 100644 index 00000000000000..aa1e523a0989e4 --- /dev/null +++ b/docs/data/system/getting-started/usage/ContainerQueries.tsx @@ -0,0 +1,88 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; + +export default function ContainerQueries() { + return ( + + + + +
+ + 123 Main St, Phoenix AZ + + + $280,000 — $310,000 + +
+ + Confidence score: 85% + +
+
+
+ ); +} diff --git a/docs/data/system/getting-started/usage/usage.md b/docs/data/system/getting-started/usage/usage.md index 487340ad2b1585..1e5d3de608f2f2 100644 --- a/docs/data/system/getting-started/usage/usage.md +++ b/docs/data/system/getting-started/usage/usage.md @@ -291,6 +291,19 @@ The following demo shows how to define a set of breakpoints using the object syn {{"demo": "BreakpointsAsObject.js"}} +:::info +📣 Starting from v6, the object structure supports [container queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries) shorthand with `@`. + +We recommend you to check the [browser support](https://caniuse.com/?search=container%20que) before using CSS container queries. +::: + +The shorthand syntax is `@{breakpoint}/{container}`: + +- **breakpoint**: a number for `px` unit or a breakpoint key (e.g. `sm`, `md`, `lg`, `xl` for default breakpoints) or a valid CSS value (e.g. `40em`). +- **container** (optional): the name of the [containment context](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries#naming_containment_contexts). + +{{"demo": "ContainerQueries.js"}} + #### Breakpoints as an array The second option is to define your breakpoints as an array, from smallest to largest. diff --git a/docs/package.json b/docs/package.json index 315a51a02a861e..f8ea8e340c9db7 100644 --- a/docs/package.json +++ b/docs/package.json @@ -20,7 +20,6 @@ }, "dependencies": { "@babel/core": "^7.24.4", - "@babel/plugin-transform-object-assign": "^7.24.1", "@babel/runtime": "^7.24.4", "@babel/runtime-corejs2": "^7.24.4", "@docsearch/react": "^3.6.0", diff --git a/docs/pages/_app.js b/docs/pages/_app.js index 70dc207b752e66..7ba45523219f4e 100644 --- a/docs/pages/_app.js +++ b/docs/pages/_app.js @@ -18,7 +18,7 @@ import joyPages from 'docs/data/joy/pages'; import systemPages from 'docs/data/system/pages'; import PageContext from 'docs/src/modules/components/PageContext'; import GoogleAnalytics from 'docs/src/modules/components/GoogleAnalytics'; -import { CodeCopyProvider } from 'docs/src/modules/utils/CodeCopy'; +import { CodeCopyProvider } from '@mui/docs/CodeCopy'; import { ThemeProvider } from 'docs/src/modules/components/ThemeContext'; import { CodeVariantProvider } from 'docs/src/modules/utils/codeVariant'; import { CodeStylingProvider } from 'docs/src/modules/utils/codeStylingSolution'; diff --git a/docs/pages/blog/2020-developer-survey-results.md b/docs/pages/blog/2020-developer-survey-results.md index 42f611ecce9484..fe4f383a04f160 100644 --- a/docs/pages/blog/2020-developer-survey-results.md +++ b/docs/pages/blog/2020-developer-survey-results.md @@ -315,5 +315,5 @@ We will run a similar survey next year to keep track of our progress. If you want to continue to influence our roadmap, please upvote 👍 the issues you are the most interested in on GitHub. -How to upvote on GitHub +How to upvote on GitHub

Help us prioritize by upvoting.

diff --git a/docs/pages/blog/mui-core-v5.md b/docs/pages/blog/mui-core-v5.md index 688cf79b04aadd..868808c1e65088 100644 --- a/docs/pages/blog/mui-core-v5.md +++ b/docs/pages/blog/mui-core-v5.md @@ -477,7 +477,7 @@ Although each product has its unique vision and mission statements, they complem - Vision: Create the last UI component library developers will ever need. High quality, consistent, feature-rich, and covering the most frequent/challenging use-cases. - Mission: Make building rich, data-intensive, dynamic apps a breeze. -MUI Core has a positive cash flow thanks to its paid templates, design assets, ads on the documentation, and backers/sponsors (❤️). The [MIT](https://tldrlegal.com/license/mit-license) license model works great for it. +MUI Core has a positive cash flow thanks to its paid templates, design assets, ads on the documentation, and backers/sponsors (❤️). The [MIT](https://www.tldrlegal.com/license/mit-license) license model works great for it. However, none of these revenue sources would scale with the outcome and amount of work required for MUI X. It's why we are using an [open core license model](https://en.m.wikipedia.org/wiki/Open-core_model) for this new product. diff --git a/docs/pages/experiments/docs/DemoMultiTabs.js b/docs/pages/experiments/docs/DemoMultiTabs.js new file mode 100644 index 00000000000000..77f396e925cec7 --- /dev/null +++ b/docs/pages/experiments/docs/DemoMultiTabs.js @@ -0,0 +1,37 @@ +import * as React from 'react'; +import { BarChart } from '@mui/x-charts/BarChart'; +import { axisClasses } from '@mui/x-charts'; +import dataset from './dataset.json'; + +const chartSetting = { + yAxis: [ + { + label: 'rainfall (mm)', + }, + ], + width: 500, + height: 300, + sx: { + [`.${axisClasses.left} .${axisClasses.label}`]: { + transform: 'translate(-20px, 0)', + }, + }, +}; + +const valueFormatter = (value) => `${value}mm`; + +export default function BarsDataset() { + return ( + + ); +} diff --git a/docs/pages/experiments/docs/dataset.json b/docs/pages/experiments/docs/dataset.json new file mode 100644 index 00000000000000..c3c44c6bd91174 --- /dev/null +++ b/docs/pages/experiments/docs/dataset.json @@ -0,0 +1,88 @@ +{ + "data": [ + { + "london": 59, + "paris": 57, + "newYork": 86, + "seoul": 21, + "month": "Jan" + }, + { + "london": 50, + "paris": 52, + "newYork": 78, + "seoul": 28, + "month": "Fev" + }, + { + "london": 47, + "paris": 53, + "newYork": 106, + "seoul": 41, + "month": "Mar" + }, + { + "london": 54, + "paris": 56, + "newYork": 92, + "seoul": 73, + "month": "Apr" + }, + { + "london": 57, + "paris": 69, + "newYork": 92, + "seoul": 99, + "month": "May" + }, + { + "london": 60, + "paris": 63, + "newYork": 103, + "seoul": 144, + "month": "June" + }, + { + "london": 59, + "paris": 60, + "newYork": 105, + "seoul": 319, + "month": "July" + }, + { + "london": 65, + "paris": 60, + "newYork": 106, + "seoul": 249, + "month": "Aug" + }, + { + "london": 51, + "paris": 51, + "newYork": 95, + "seoul": 131, + "month": "Sept" + }, + { + "london": 60, + "paris": 65, + "newYork": 97, + "seoul": 55, + "month": "Oct" + }, + { + "london": 67, + "paris": 64, + "newYork": 76, + "seoul": 48, + "month": "Nov" + }, + { + "london": 61, + "paris": 70, + "newYork": 103, + "seoul": 25, + "month": "Dec" + } + ] +} diff --git a/docs/pages/experiments/docs/demos.md b/docs/pages/experiments/docs/demos.md index 5a630ed5a063fb..8a0d33434a5485 100644 --- a/docs/pages/experiments/docs/demos.md +++ b/docs/pages/experiments/docs/demos.md @@ -36,3 +36,7 @@ So, it renders the "outlined" background variant. ## "hideToolbar": true, "bg": "inline" {{"demo": "DemoInDocs.js", "hideToolbar": true, "bg": "inline"}} + +## Multiple Tabs demo + +{{"demo": "DemoMultiTabs.js" }} diff --git a/docs/pages/material-ui/about-the-lab.js b/docs/pages/material-ui/about-the-lab.js index c0961474d0a02f..c028dfbaea4932 100644 --- a/docs/pages/material-ui/about-the-lab.js +++ b/docs/pages/material-ui/about-the-lab.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/about-the-lab/about-the-lab.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/icons.js b/docs/pages/material-ui/icons.js index 567b92d1ef1e9c..07de341709f0e8 100644 --- a/docs/pages/material-ui/icons.js +++ b/docs/pages/material-ui/icons.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/icons/icons.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/material-icons.js b/docs/pages/material-ui/material-icons.js index 8bdbc9d6729753..88344171346946 100644 --- a/docs/pages/material-ui/material-icons.js +++ b/docs/pages/material-ui/material-icons.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/material-icons/material-icons.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-accordion.js b/docs/pages/material-ui/react-accordion.js index 26291b13befe10..1c7e53c5306d51 100644 --- a/docs/pages/material-ui/react-accordion.js +++ b/docs/pages/material-ui/react-accordion.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/accordion/accordion.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-alert.js b/docs/pages/material-ui/react-alert.js index 84552123aacd05..5ff0b8e14c5653 100644 --- a/docs/pages/material-ui/react-alert.js +++ b/docs/pages/material-ui/react-alert.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/alert/alert.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-app-bar.js b/docs/pages/material-ui/react-app-bar.js index 2a58a66711a75c..84efc04925f535 100644 --- a/docs/pages/material-ui/react-app-bar.js +++ b/docs/pages/material-ui/react-app-bar.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/app-bar/app-bar.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-autocomplete.js b/docs/pages/material-ui/react-autocomplete.js index 1ec006a4f20a34..8902dffd65db28 100644 --- a/docs/pages/material-ui/react-autocomplete.js +++ b/docs/pages/material-ui/react-autocomplete.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/autocomplete/autocomplete.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-avatar.js b/docs/pages/material-ui/react-avatar.js index 0c74ca45a6b3d7..fb69aa1b721484 100644 --- a/docs/pages/material-ui/react-avatar.js +++ b/docs/pages/material-ui/react-avatar.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/avatars/avatars.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-backdrop.js b/docs/pages/material-ui/react-backdrop.js index cac8c8788807d3..9246804b99e358 100644 --- a/docs/pages/material-ui/react-backdrop.js +++ b/docs/pages/material-ui/react-backdrop.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/backdrop/backdrop.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-badge.js b/docs/pages/material-ui/react-badge.js index 096d87c87f47f8..bf7e789c24b2dd 100644 --- a/docs/pages/material-ui/react-badge.js +++ b/docs/pages/material-ui/react-badge.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/badges/badges.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-bottom-navigation.js b/docs/pages/material-ui/react-bottom-navigation.js index edefefdea6dbce..133c440143c6e5 100644 --- a/docs/pages/material-ui/react-bottom-navigation.js +++ b/docs/pages/material-ui/react-bottom-navigation.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/bottom-navigation/bottom-navigation.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-box.js b/docs/pages/material-ui/react-box.js index e9439033fd229e..350423ce30f00b 100644 --- a/docs/pages/material-ui/react-box.js +++ b/docs/pages/material-ui/react-box.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/box/box.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-breadcrumbs.js b/docs/pages/material-ui/react-breadcrumbs.js index 0cd1f21647d87d..f64f67b09fd1d0 100644 --- a/docs/pages/material-ui/react-breadcrumbs.js +++ b/docs/pages/material-ui/react-breadcrumbs.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/breadcrumbs/breadcrumbs.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-card.js b/docs/pages/material-ui/react-card.js index 67fa766a02990f..8fb6f72afe1968 100644 --- a/docs/pages/material-ui/react-card.js +++ b/docs/pages/material-ui/react-card.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/cards/cards.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-checkbox.js b/docs/pages/material-ui/react-checkbox.js index 16ebde8c0e0a9a..e6c610d0dd0ba6 100644 --- a/docs/pages/material-ui/react-checkbox.js +++ b/docs/pages/material-ui/react-checkbox.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/checkboxes/checkboxes.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-chip.js b/docs/pages/material-ui/react-chip.js index 548d240e966a38..9af1f9e4bd4785 100644 --- a/docs/pages/material-ui/react-chip.js +++ b/docs/pages/material-ui/react-chip.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/chips/chips.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-click-away-listener.js b/docs/pages/material-ui/react-click-away-listener.js index 8b51c04a6b1cf2..fb964ae06144a5 100644 --- a/docs/pages/material-ui/react-click-away-listener.js +++ b/docs/pages/material-ui/react-click-away-listener.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/click-away-listener/click-away-listener.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-container.js b/docs/pages/material-ui/react-container.js index d5d647dc828dfa..974047436f4464 100644 --- a/docs/pages/material-ui/react-container.js +++ b/docs/pages/material-ui/react-container.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/container/container.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-css-baseline.js b/docs/pages/material-ui/react-css-baseline.js index 68d27f2b41af7c..fb43be46fc6ea0 100644 --- a/docs/pages/material-ui/react-css-baseline.js +++ b/docs/pages/material-ui/react-css-baseline.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/css-baseline/css-baseline.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-dialog.js b/docs/pages/material-ui/react-dialog.js index 537a476553a2eb..2ded281a496a7a 100644 --- a/docs/pages/material-ui/react-dialog.js +++ b/docs/pages/material-ui/react-dialog.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/dialogs/dialogs.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-divider.js b/docs/pages/material-ui/react-divider.js index 7c32aa1c784f47..4ca13335073941 100644 --- a/docs/pages/material-ui/react-divider.js +++ b/docs/pages/material-ui/react-divider.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/dividers/dividers.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-drawer.js b/docs/pages/material-ui/react-drawer.js index 6d8905e8275778..8aac39efcdfaca 100644 --- a/docs/pages/material-ui/react-drawer.js +++ b/docs/pages/material-ui/react-drawer.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/drawers/drawers.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-floating-action-button.js b/docs/pages/material-ui/react-floating-action-button.js index 681bebda025a79..66a5658de6a2cf 100644 --- a/docs/pages/material-ui/react-floating-action-button.js +++ b/docs/pages/material-ui/react-floating-action-button.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/floating-action-button/floating-action-button.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-grid.js b/docs/pages/material-ui/react-grid.js index 78ddcb6ee321ee..2ffecb31f92132 100644 --- a/docs/pages/material-ui/react-grid.js +++ b/docs/pages/material-ui/react-grid.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/grid/grid.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-grid2.js b/docs/pages/material-ui/react-grid2.js index b4dbffc77707c3..99e253537cc1a6 100644 --- a/docs/pages/material-ui/react-grid2.js +++ b/docs/pages/material-ui/react-grid2.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/grid2/grid2.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-hidden.js b/docs/pages/material-ui/react-hidden.js index 51cccdd38378a2..6f2d3fabf003e6 100644 --- a/docs/pages/material-ui/react-hidden.js +++ b/docs/pages/material-ui/react-hidden.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/hidden/hidden.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-image-list.js b/docs/pages/material-ui/react-image-list.js index f0f150afe7277e..79a5925eb05e95 100644 --- a/docs/pages/material-ui/react-image-list.js +++ b/docs/pages/material-ui/react-image-list.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/image-list/image-list.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-link.js b/docs/pages/material-ui/react-link.js index c288ac87affe2b..6a3c6bbb71149c 100644 --- a/docs/pages/material-ui/react-link.js +++ b/docs/pages/material-ui/react-link.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/links/links.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-list.js b/docs/pages/material-ui/react-list.js index c78ea0de33ba26..5ff15e226ab828 100644 --- a/docs/pages/material-ui/react-list.js +++ b/docs/pages/material-ui/react-list.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/lists/lists.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-masonry.js b/docs/pages/material-ui/react-masonry.js index 56633ff2e8d6d0..8d60dbed5893bf 100644 --- a/docs/pages/material-ui/react-masonry.js +++ b/docs/pages/material-ui/react-masonry.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/masonry/masonry.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-menu.js b/docs/pages/material-ui/react-menu.js index 33113e15a78f28..adeeb30a02ab9c 100644 --- a/docs/pages/material-ui/react-menu.js +++ b/docs/pages/material-ui/react-menu.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/menus/menus.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-modal.js b/docs/pages/material-ui/react-modal.js index 46d8fc442d7d0d..2fd8152936ee4d 100644 --- a/docs/pages/material-ui/react-modal.js +++ b/docs/pages/material-ui/react-modal.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/modal/modal.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-no-ssr.js b/docs/pages/material-ui/react-no-ssr.js index ee83206a71178d..3b2bf08f6f15a8 100644 --- a/docs/pages/material-ui/react-no-ssr.js +++ b/docs/pages/material-ui/react-no-ssr.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/no-ssr/no-ssr.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-pagination.js b/docs/pages/material-ui/react-pagination.js index 9a48a0ed86d11b..fe739abc49562b 100644 --- a/docs/pages/material-ui/react-pagination.js +++ b/docs/pages/material-ui/react-pagination.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/pagination/pagination.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-paper.js b/docs/pages/material-ui/react-paper.js index 41ece6824d65db..1d3530c004087e 100644 --- a/docs/pages/material-ui/react-paper.js +++ b/docs/pages/material-ui/react-paper.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/paper/paper.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-popover.js b/docs/pages/material-ui/react-popover.js index 48cba31980a1c7..9bbd2deb5f5e5f 100644 --- a/docs/pages/material-ui/react-popover.js +++ b/docs/pages/material-ui/react-popover.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/popover/popover.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-popper.js b/docs/pages/material-ui/react-popper.js index 6ab2616c48f0af..f228bcde1491d2 100644 --- a/docs/pages/material-ui/react-popper.js +++ b/docs/pages/material-ui/react-popper.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/popper/popper.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-portal.js b/docs/pages/material-ui/react-portal.js index 07a891e7658072..ad08e80adecda0 100644 --- a/docs/pages/material-ui/react-portal.js +++ b/docs/pages/material-ui/react-portal.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/portal/portal.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-progress.js b/docs/pages/material-ui/react-progress.js index 85e37159117a78..e4a2a09cd1db57 100644 --- a/docs/pages/material-ui/react-progress.js +++ b/docs/pages/material-ui/react-progress.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/progress/progress.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-radio-button.js b/docs/pages/material-ui/react-radio-button.js index b881c8a18b6f80..e8db25df8ce071 100644 --- a/docs/pages/material-ui/react-radio-button.js +++ b/docs/pages/material-ui/react-radio-button.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/radio-buttons/radio-buttons.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-rating.js b/docs/pages/material-ui/react-rating.js index ece9b071bf2aaa..a4fba7027ca9c6 100644 --- a/docs/pages/material-ui/react-rating.js +++ b/docs/pages/material-ui/react-rating.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/rating/rating.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-select.js b/docs/pages/material-ui/react-select.js index d5d9459ff95307..e158606f9199b5 100644 --- a/docs/pages/material-ui/react-select.js +++ b/docs/pages/material-ui/react-select.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/selects/selects.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-skeleton.js b/docs/pages/material-ui/react-skeleton.js index 40aeb2ea2b2bbe..2ff3091f92006f 100644 --- a/docs/pages/material-ui/react-skeleton.js +++ b/docs/pages/material-ui/react-skeleton.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/skeleton/skeleton.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-slider.js b/docs/pages/material-ui/react-slider.js index 2762b71458c831..e11443c469eaf4 100644 --- a/docs/pages/material-ui/react-slider.js +++ b/docs/pages/material-ui/react-slider.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/slider/slider.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-snackbar.js b/docs/pages/material-ui/react-snackbar.js index ef9cd9110e75e7..b1f6c4efa1a6a3 100644 --- a/docs/pages/material-ui/react-snackbar.js +++ b/docs/pages/material-ui/react-snackbar.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/snackbars/snackbars.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-speed-dial.js b/docs/pages/material-ui/react-speed-dial.js index b51a5eece1a78d..3ed86f5fde2a05 100644 --- a/docs/pages/material-ui/react-speed-dial.js +++ b/docs/pages/material-ui/react-speed-dial.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/speed-dial/speed-dial.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-stack.js b/docs/pages/material-ui/react-stack.js index 44e36ffc1eeff3..af230dcf002b3f 100644 --- a/docs/pages/material-ui/react-stack.js +++ b/docs/pages/material-ui/react-stack.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/stack/stack.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-stepper.js b/docs/pages/material-ui/react-stepper.js index f56275b1654708..7a389033833b41 100644 --- a/docs/pages/material-ui/react-stepper.js +++ b/docs/pages/material-ui/react-stepper.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/steppers/steppers.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-switch.js b/docs/pages/material-ui/react-switch.js index d8d850f538c943..59f5eae99895ea 100644 --- a/docs/pages/material-ui/react-switch.js +++ b/docs/pages/material-ui/react-switch.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/switches/switches.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-table.js b/docs/pages/material-ui/react-table.js index 10b6203c6b830b..398a5a9a46a551 100644 --- a/docs/pages/material-ui/react-table.js +++ b/docs/pages/material-ui/react-table.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/table/table.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-tabs.js b/docs/pages/material-ui/react-tabs.js index 51e69d3a7630ae..2406fcc3a665ce 100644 --- a/docs/pages/material-ui/react-tabs.js +++ b/docs/pages/material-ui/react-tabs.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/tabs/tabs.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-text-field.js b/docs/pages/material-ui/react-text-field.js index f7756ce29ddd50..c3f07ee5467c48 100644 --- a/docs/pages/material-ui/react-text-field.js +++ b/docs/pages/material-ui/react-text-field.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/text-fields/text-fields.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-textarea-autosize.js b/docs/pages/material-ui/react-textarea-autosize.js index 7d1def906c2aec..4c87d54571af4e 100644 --- a/docs/pages/material-ui/react-textarea-autosize.js +++ b/docs/pages/material-ui/react-textarea-autosize.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/textarea-autosize/textarea-autosize.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-timeline.js b/docs/pages/material-ui/react-timeline.js index 83869d3365841c..87167e7220fba0 100644 --- a/docs/pages/material-ui/react-timeline.js +++ b/docs/pages/material-ui/react-timeline.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/timeline/timeline.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-toggle-button.js b/docs/pages/material-ui/react-toggle-button.js index 822839b3fad4a8..c5df44f259cd62 100644 --- a/docs/pages/material-ui/react-toggle-button.js +++ b/docs/pages/material-ui/react-toggle-button.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/toggle-button/toggle-button.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-tooltip.js b/docs/pages/material-ui/react-tooltip.js index 4cd5c404f860db..3893fc2aed36a6 100644 --- a/docs/pages/material-ui/react-tooltip.js +++ b/docs/pages/material-ui/react-tooltip.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/tooltips/tooltips.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-transfer-list.js b/docs/pages/material-ui/react-transfer-list.js index 952f286ac40fc6..2ae58dcfb4ff3b 100644 --- a/docs/pages/material-ui/react-transfer-list.js +++ b/docs/pages/material-ui/react-transfer-list.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/transfer-list/transfer-list.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-typography.js b/docs/pages/material-ui/react-typography.js index f5014b469b0416..4a0b190155e9ea 100644 --- a/docs/pages/material-ui/react-typography.js +++ b/docs/pages/material-ui/react-typography.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/typography/typography.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/react-use-media-query.js b/docs/pages/material-ui/react-use-media-query.js index 44e229472b0685..ae24bc8ce38672 100644 --- a/docs/pages/material-ui/react-use-media-query.js +++ b/docs/pages/material-ui/react-use-media-query.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/use-media-query/use-media-query.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/pages/material-ui/transitions.js b/docs/pages/material-ui/transitions.js index c60770e5e2c518..2647d9bc2870e8 100644 --- a/docs/pages/material-ui/transitions.js +++ b/docs/pages/material-ui/transitions.js @@ -1,7 +1,12 @@ import * as React from 'react'; -import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2'; +import AppFrame from 'docs/src/modules/components/AppFrame'; import * as pageProps from 'docs/data/material/components/transitions/transitions.md?muiMarkdown'; export default function Page() { return ; } + +Page.getLayout = (page) => { + return {page}; +}; diff --git a/docs/public/static/error-codes.json b/docs/public/static/error-codes.json index a6486f38f45d49..c5acc584689575 100644 --- a/docs/public/static/error-codes.json +++ b/docs/public/static/error-codes.json @@ -18,5 +18,6 @@ "17": "MUI: Expected valid input target. Did you use a custom `slots.input` and forget to forward refs? See https://mui.com/r/input-component-ref-interface for more info.", "18": "MUI: `vars` is a private field used for CSS variables support.\nPlease use another name.", "19": "MUI: `useColorScheme` must be called under ", - "20": "MUI: The `experimental_sx` has been moved to `theme.unstable_sx`.For more details, see https://github.com/mui/material-ui/pull/35150." + "20": "MUI: The `experimental_sx` has been moved to `theme.unstable_sx`.For more details, see https://github.com/mui/material-ui/pull/35150.", + "21": "MUI: The provided shorthand %s is invalid. The format should be `@` or `@/`.\nFor example, `@sm` or `@600` or `@40rem/sidebar`." } diff --git a/docs/public/static/images/templates/blog-dark.png b/docs/public/static/images/templates/blog-dark.png new file mode 100644 index 00000000000000..03ad60a492a907 Binary files /dev/null and b/docs/public/static/images/templates/blog-dark.png differ diff --git a/docs/public/static/images/templates/blog-light.png b/docs/public/static/images/templates/blog-light.png new file mode 100644 index 00000000000000..ff252d1e7aa33e Binary files /dev/null and b/docs/public/static/images/templates/blog-light.png differ diff --git a/docs/public/static/images/templates/blog.png b/docs/public/static/images/templates/blog.png deleted file mode 100644 index debe0f3ed3a9b4..00000000000000 Binary files a/docs/public/static/images/templates/blog.png and /dev/null differ diff --git a/docs/public/static/images/templates/checkout-dark.png b/docs/public/static/images/templates/checkout-dark.png new file mode 100644 index 00000000000000..6269d11fed5dd8 Binary files /dev/null and b/docs/public/static/images/templates/checkout-dark.png differ diff --git a/docs/public/static/images/templates/checkout-light.png b/docs/public/static/images/templates/checkout-light.png new file mode 100644 index 00000000000000..6bdda36f908a5a Binary files /dev/null and b/docs/public/static/images/templates/checkout-light.png differ diff --git a/docs/public/static/images/templates/checkout.png b/docs/public/static/images/templates/checkout.png deleted file mode 100644 index e5cfba2cd01c55..00000000000000 Binary files a/docs/public/static/images/templates/checkout.png and /dev/null differ diff --git a/docs/public/static/images/templates/dashboard-dark.png b/docs/public/static/images/templates/dashboard-dark.png new file mode 100644 index 00000000000000..42984725db85dc Binary files /dev/null and b/docs/public/static/images/templates/dashboard-dark.png differ diff --git a/docs/public/static/images/templates/dashboard-light.png b/docs/public/static/images/templates/dashboard-light.png new file mode 100644 index 00000000000000..e93b5e52c57954 Binary files /dev/null and b/docs/public/static/images/templates/dashboard-light.png differ diff --git a/docs/public/static/images/templates/dashboard.png b/docs/public/static/images/templates/dashboard.png deleted file mode 100644 index 2a10b08116f94f..00000000000000 Binary files a/docs/public/static/images/templates/dashboard.png and /dev/null differ diff --git a/docs/public/static/images/templates/landing-page-dark.png b/docs/public/static/images/templates/landing-page-dark.png new file mode 100644 index 00000000000000..e48adbb205b1f3 Binary files /dev/null and b/docs/public/static/images/templates/landing-page-dark.png differ diff --git a/docs/public/static/images/templates/landing-page-light.png b/docs/public/static/images/templates/landing-page-light.png new file mode 100644 index 00000000000000..b6d375da2a36c0 Binary files /dev/null and b/docs/public/static/images/templates/landing-page-light.png differ diff --git a/docs/public/static/images/templates/landing-page.png b/docs/public/static/images/templates/landing-page.png deleted file mode 100644 index a6dfeac3242598..00000000000000 Binary files a/docs/public/static/images/templates/landing-page.png and /dev/null differ diff --git a/docs/public/static/images/templates/pricing.png b/docs/public/static/images/templates/pricing.png deleted file mode 100644 index 745f03cbeb7689..00000000000000 Binary files a/docs/public/static/images/templates/pricing.png and /dev/null differ diff --git a/docs/public/static/images/templates/sign-in-dark.png b/docs/public/static/images/templates/sign-in-dark.png new file mode 100644 index 00000000000000..a67406f45f8a81 Binary files /dev/null and b/docs/public/static/images/templates/sign-in-dark.png differ diff --git a/docs/public/static/images/templates/sign-in-light.png b/docs/public/static/images/templates/sign-in-light.png new file mode 100644 index 00000000000000..888b41cff9c4f5 Binary files /dev/null and b/docs/public/static/images/templates/sign-in-light.png differ diff --git a/docs/public/static/images/templates/sign-in-side-dark.png b/docs/public/static/images/templates/sign-in-side-dark.png new file mode 100644 index 00000000000000..b3332ca4079314 Binary files /dev/null and b/docs/public/static/images/templates/sign-in-side-dark.png differ diff --git a/docs/public/static/images/templates/sign-in-side-light.png b/docs/public/static/images/templates/sign-in-side-light.png new file mode 100644 index 00000000000000..b8180488e28e20 Binary files /dev/null and b/docs/public/static/images/templates/sign-in-side-light.png differ diff --git a/docs/public/static/images/templates/sign-in-side.png b/docs/public/static/images/templates/sign-in-side.png deleted file mode 100644 index fb00a2d01160fb..00000000000000 Binary files a/docs/public/static/images/templates/sign-in-side.png and /dev/null differ diff --git a/docs/public/static/images/templates/sign-in.png b/docs/public/static/images/templates/sign-in.png deleted file mode 100644 index 597b57ae1d1356..00000000000000 Binary files a/docs/public/static/images/templates/sign-in.png and /dev/null differ diff --git a/docs/public/static/images/templates/sign-up-dark.png b/docs/public/static/images/templates/sign-up-dark.png new file mode 100644 index 00000000000000..ad19c16a0de062 Binary files /dev/null and b/docs/public/static/images/templates/sign-up-dark.png differ diff --git a/docs/public/static/images/templates/sign-up-light.png b/docs/public/static/images/templates/sign-up-light.png new file mode 100644 index 00000000000000..514db1bcce3d1a Binary files /dev/null and b/docs/public/static/images/templates/sign-up-light.png differ diff --git a/docs/public/static/images/templates/sign-up.png b/docs/public/static/images/templates/sign-up.png deleted file mode 100644 index b92eca0b42a10a..00000000000000 Binary files a/docs/public/static/images/templates/sign-up.png and /dev/null differ diff --git a/docs/public/static/images/templates/sticky-footer-dark.png b/docs/public/static/images/templates/sticky-footer-dark.png new file mode 100644 index 00000000000000..276cd14a764555 Binary files /dev/null and b/docs/public/static/images/templates/sticky-footer-dark.png differ diff --git a/docs/public/static/images/templates/sticky-footer-light.png b/docs/public/static/images/templates/sticky-footer-light.png new file mode 100644 index 00000000000000..5a44b3e9168bfb Binary files /dev/null and b/docs/public/static/images/templates/sticky-footer-light.png differ diff --git a/docs/public/static/images/templates/sticky-footer.png b/docs/public/static/images/templates/sticky-footer.png deleted file mode 100644 index 72f56aab9cc854..00000000000000 Binary files a/docs/public/static/images/templates/sticky-footer.png and /dev/null differ diff --git a/docs/public/static/images/themes-display-dark.png b/docs/public/static/images/themes-display-dark.png new file mode 100644 index 00000000000000..bf9e83555f2b25 Binary files /dev/null and b/docs/public/static/images/themes-display-dark.png differ diff --git a/docs/public/static/images/themes-display-light.png b/docs/public/static/images/themes-display-light.png new file mode 100644 index 00000000000000..4b18dd868eb00f Binary files /dev/null and b/docs/public/static/images/themes-display-light.png differ diff --git a/docs/public/static/images/themes-display.png b/docs/public/static/images/themes-display.png deleted file mode 100644 index 43069c6f6855bf..00000000000000 Binary files a/docs/public/static/images/themes-display.png and /dev/null differ diff --git a/docs/src/components/about/HowToSupport.tsx b/docs/src/components/about/HowToSupport.tsx index 99bc248bd1db31..128763cae41126 100644 --- a/docs/src/components/about/HowToSupport.tsx +++ b/docs/src/components/about/HowToSupport.tsx @@ -27,17 +27,12 @@ function Widget({ ({ - p: 4, + p: 3, height: '100%', display: 'flex', flexDirection: 'column', - borderRadius: '12px', - border: '1px solid', - borderColor: 'grey.100', background: `${(theme.vars || theme).palette.gradients.linearSubtle}`, ...theme.applyDarkStyles({ - bgcolor: 'primaryDark.900', - borderColor: 'primaryDark.700', background: `${(theme.vars || theme).palette.gradients.linearSubtle}`, }), })} @@ -85,12 +80,12 @@ export default function HowToSupport() { @@ -146,12 +141,12 @@ export default function HowToSupport() {
@@ -173,12 +168,12 @@ export default function HowToSupport() { diff --git a/docs/src/components/action/NpmCopyButton.tsx b/docs/src/components/action/NpmCopyButton.tsx index e74acf024aae3b..de9efd9e45a99b 100644 --- a/docs/src/components/action/NpmCopyButton.tsx +++ b/docs/src/components/action/NpmCopyButton.tsx @@ -34,11 +34,11 @@ const Button = styled('button')(({ theme }) => ({ }), WebkitTapHighlightColor: 'transparent', WebkitFontSmoothing: 'subpixel-antialiased', - color: (theme.vars || theme).palette.grey[600], + color: (theme.vars || theme).palette.text.tertiary, '&:hover, &:focus-visible': { color: (theme.vars || theme).palette.primary.main, '@media (hover: none)': { - color: (theme.vars || theme).palette.grey[600], + color: (theme.vars || theme).palette.text.tertiary, }, }, '& svg': { diff --git a/docs/src/components/home/AdvancedShowcase.tsx b/docs/src/components/home/AdvancedShowcase.tsx index 59caeeccbc97ad..dcf4b50acd53c6 100644 --- a/docs/src/components/home/AdvancedShowcase.tsx +++ b/docs/src/components/home/AdvancedShowcase.tsx @@ -5,8 +5,8 @@ import Paper from '@mui/material/Paper'; import Typography from '@mui/material/Typography'; import Divider from '@mui/material/Divider'; import ShowcaseContainer from 'docs/src/components/home/ShowcaseContainer'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; -import MarkdownElement from 'docs/src/components/markdown/MarkdownElement'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; +import { MarkdownElement } from '@mui/docs/MarkdownElement'; import XGridGlobalStyles from 'docs/src/components/home/XGridGlobalStyles'; import ProgressBar from 'docs/src/components/x-grid/ProgressBar'; import EditProgress from 'docs/src/components/x-grid/EditProgress'; diff --git a/docs/src/components/home/CoreShowcase.tsx b/docs/src/components/home/CoreShowcase.tsx index b2483ab7abe165..0277cad4422d1d 100644 --- a/docs/src/components/home/CoreShowcase.tsx +++ b/docs/src/components/home/CoreShowcase.tsx @@ -2,8 +2,8 @@ import * as React from 'react'; import { alpha, ThemeProvider, createTheme, useTheme } from '@mui/material/styles'; import Box from '@mui/material/Box'; import Button, { buttonClasses } from '@mui/material/Button'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; -import MarkdownElement from 'docs/src/components/markdown/MarkdownElement'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; +import { MarkdownElement } from '@mui/docs/MarkdownElement'; import MaterialDesignDemo, { componentCode } from 'docs/src/components/home/MaterialDesignDemo'; import ShowcaseContainer from 'docs/src/components/home/ShowcaseContainer'; import PointerContainer, { Data } from 'docs/src/components/home/ElementPointer'; diff --git a/docs/src/components/home/MaterialDesignDemo.tsx b/docs/src/components/home/MaterialDesignDemo.tsx index ec6f9a3d8f516b..459d43967408b0 100644 --- a/docs/src/components/home/MaterialDesignDemo.tsx +++ b/docs/src/components/home/MaterialDesignDemo.tsx @@ -24,7 +24,7 @@ export const componentCode = ` label={active ? 'Active' : 'Inactive'} color={active ? 'success' : 'default'} /> - + @@ -69,7 +69,7 @@ export default function MaterialDesignDemo(props: CardProps) { zIndex: 2, }} /> - + - + - + {renderItem(0)} {renderItem(1)} {renderItem(2)} {renderItem(3)} - + {renderItem(4)} {renderItem(5)} {renderItem(6)} {renderItem(7)} - + ({ diff --git a/docs/src/components/pricing/PricingList.tsx b/docs/src/components/pricing/PricingList.tsx index 46eceaabc760a6..3ca9c94cea8a6f 100644 --- a/docs/src/components/pricing/PricingList.tsx +++ b/docs/src/components/pricing/PricingList.tsx @@ -117,7 +117,7 @@ export default function PricingList() { theme.applyDarkStyles({ '& .MuiTab-root': { '&.Mui-selected': { - bgcolor: 'primaryDark.700', + bgcolor: 'primaryDark.800', }, }, }), diff --git a/docs/src/components/pricing/PricingWhatToExpect.tsx b/docs/src/components/pricing/PricingWhatToExpect.tsx index ffeaea5868b4e6..13066ac27238de 100644 --- a/docs/src/components/pricing/PricingWhatToExpect.tsx +++ b/docs/src/components/pricing/PricingWhatToExpect.tsx @@ -36,15 +36,9 @@ export default function PricingWhatToExpect() { }} > - + - + Required quantity @@ -53,6 +47,7 @@ export default function PricingWhatToExpect() { developers contributing changes to the front-end code of the projects that use the software.
+
You can learn more about this in{' '}
- + - + Perpetual license model @@ -93,15 +82,9 @@ export default function PricingWhatToExpect() { - + - + Perpetual vs. Annual license model @@ -118,15 +101,9 @@ export default function PricingWhatToExpect() { - + - + Annual license model @@ -152,15 +129,9 @@ export default function PricingWhatToExpect() { - + - + Maintenance and support @@ -170,21 +141,17 @@ export default function PricingWhatToExpect() { learn more about support {' '} - in the docs. Note that, except for critical issues, such as security flaws, we release - bug fixes and other improvements on top of the latest version, instead of patching older - versions. + in the docs. +
+
+ Note that, except for critical issues, such as security flaws, we release bug fixes and + other improvements on top of the latest version, instead of patching older versions.
- + - + Volume discounts @@ -192,6 +159,7 @@ export default function PricingWhatToExpect() { The Pro plan is capped at 10 developers licensed; you do not need to pay for additional licenses for more than 10 developers.
+
You can contact sales for a volume discount when licensing over 25 developers under the Premium plan. diff --git a/docs/src/components/productBaseUI/BaseUIComponents.tsx b/docs/src/components/productBaseUI/BaseUIComponents.tsx index dea8227b45d20d..d7e1e013218a76 100644 --- a/docs/src/components/productBaseUI/BaseUIComponents.tsx +++ b/docs/src/components/productBaseUI/BaseUIComponents.tsx @@ -20,8 +20,8 @@ import ROUTES from 'docs/src/route'; // switcher icons -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; -import MarkdownElement from 'docs/src/components/markdown/MarkdownElement'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; +import { MarkdownElement } from '@mui/docs/MarkdownElement'; import BaseButtonDemo from './components/BaseButtonDemo'; import BaseMenuDemo from './components/BaseMenuDemo'; import BaseInputDemo from './components/BaseInputDemo'; diff --git a/docs/src/components/productBaseUI/BaseUICustomization.tsx b/docs/src/components/productBaseUI/BaseUICustomization.tsx index 797744435b6a22..450b60234541d8 100644 --- a/docs/src/components/productBaseUI/BaseUICustomization.tsx +++ b/docs/src/components/productBaseUI/BaseUICustomization.tsx @@ -14,8 +14,8 @@ import GradientText from 'docs/src/components/typography/GradientText'; import SectionHeadline from 'docs/src/components/typography/SectionHeadline'; import FlashCode from 'docs/src/components/animation/FlashCode'; import Frame from 'docs/src/components/action/Frame'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; -import MarkdownElement from 'docs/src/components/markdown/MarkdownElement'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; +import { MarkdownElement } from '@mui/docs/MarkdownElement'; const code = ` import clsx from 'clsx'; diff --git a/docs/src/components/productMaterial/MaterialComponents.tsx b/docs/src/components/productMaterial/MaterialComponents.tsx index 3abc1df7a2ad0a..5121c25c00c789 100644 --- a/docs/src/components/productMaterial/MaterialComponents.tsx +++ b/docs/src/components/productMaterial/MaterialComponents.tsx @@ -3,7 +3,7 @@ import { Experimental_CssVarsProvider as CssVarsProvider, alpha } from '@mui/mat import Box from '@mui/material/Box'; import Alert from '@mui/material/Alert'; import Button, { buttonClasses } from '@mui/material/Button'; -import Grid from '@mui/material/Grid'; +import Grid from '@mui/material/Unstable_Grid2'; import Stack from '@mui/material/Stack'; import Paper from '@mui/material/Paper'; import Table from '@mui/material/Table'; @@ -29,8 +29,8 @@ import Highlighter from 'docs/src/components/action/Highlighter'; import More from 'docs/src/components/action/More'; import Frame from 'docs/src/components/action/Frame'; import { customTheme } from 'docs/src/components/home/MaterialDesignComponents'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; -import MarkdownElement from 'docs/src/components/markdown/MarkdownElement'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; +import { MarkdownElement } from '@mui/docs/MarkdownElement'; import StylingInfo from 'docs/src/components/action/StylingInfo'; import ROUTES from 'docs/src/route'; @@ -118,7 +118,7 @@ export default function MaterialComponents() { return (
- + - + diff --git a/docs/src/components/productMaterial/MaterialStyling.tsx b/docs/src/components/productMaterial/MaterialStyling.tsx index 48897433cb4dc4..2565c703eea688 100644 --- a/docs/src/components/productMaterial/MaterialStyling.tsx +++ b/docs/src/components/productMaterial/MaterialStyling.tsx @@ -1,11 +1,11 @@ import * as React from 'react'; import Box from '@mui/material/Box'; -import Grid from '@mui/material/Grid'; +import Grid from '@mui/material/Unstable_Grid2'; import Typography from '@mui/material/Typography'; import DevicesOtherRoundedIcon from '@mui/icons-material/DevicesOtherRounded'; -import ContrastRoundedIcon from '@mui/icons-material/ContrastRounded'; import SwitchAccessShortcutRoundedIcon from '@mui/icons-material/SwitchAccessShortcutRounded'; import DragHandleRounded from '@mui/icons-material/DragHandleRounded'; +import StyleRoundedIcon from '@mui/icons-material/StyleRounded'; import Section from 'docs/src/layouts/Section'; import SectionHeadline from 'docs/src/components/typography/SectionHeadline'; import GradientText from 'docs/src/components/typography/GradientText'; @@ -13,8 +13,8 @@ import Item, { Group } from 'docs/src/components/action/Item'; import Highlighter from 'docs/src/components/action/Highlighter'; import Frame from 'docs/src/components/action/Frame'; import RealEstateCard from 'docs/src/components/showcase/RealEstateCard'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; -import MarkdownElement from 'docs/src/components/markdown/MarkdownElement'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; +import { MarkdownElement } from '@mui/docs/MarkdownElement'; import FlashCode from 'docs/src/components/animation/FlashCode'; const code = ` @@ -161,7 +161,7 @@ export default function MaterialStyling() { return (
- + setIndex(0)}> } + icon={} title="Leverage the tokens from your theme" description="Easily use the design tokens defined in your theme for any CSS property out there." /> @@ -195,7 +195,7 @@ export default function MaterialStyling() { - + ({ - width: { xs: 70, sm: 100 }, - height: { xs: 70, sm: 100 }, + width: { xs: 70, sm: 48 }, + height: { xs: 70, sm: 48 }, position: 'absolute', top: 'calc(50% - 50px)', p: 1.5, - color: '#FFF', + color: (theme.vars || theme).palette.primary[500], + bgcolor: '#FFF', + border: '1px solid', + borderColor: (theme.vars || theme).palette.primary[200], borderRadius: '50%', + boxShadow: `0 4px 12px ${alpha(theme.palette.grey[500], 0.2)}`, transition: '0.2s', - backdropFilter: 'blur(4px)', - bgcolor: alpha(theme.palette.primary[500], 0.5), '& > svg': { transition: '0.2s' }, '&.Mui-disabled': { opacity: 0, @@ -115,6 +123,12 @@ function ActionArea(props: ButtonBaseProps) { '&:hover, &:focus': { '& > svg': { fontSize: 28 }, }, + ...theme.applyDarkStyles({ + bgcolor: (theme.vars || theme).palette.primaryDark[900], + borderColor: (theme.vars || theme).palette.primary[900], + color: (theme.vars || theme).palette.primary[300], + boxShadow: `0 4px 12px ${alpha(theme.palette.common.black, 0.2)}`, + }), }), ...(Array.isArray(props.sx) ? props.sx : [props.sx]), ]} @@ -138,7 +152,7 @@ export default function MaterialTemplates() {
specific use case } - description="A carefully curated collection of gorgeous, fully functional templates, all powered by Material UI." + description="A carefully curated collection of gorgeous, fully functional templates." /> {DEMOS.map((name) => ( @@ -163,147 +177,160 @@ export default function MaterialTemplates() { noLinkStyle /> - - - div': { px: '12%', overflow: 'unset !important' }, - '& .react-swipeable-view-container > div': { - overflow: 'unset !important', - }, + + div': { px: '12%', overflow: 'unset !important' }, + '& .react-swipeable-view-container > div': { + overflow: 'unset !important', + }, + }} + > + setTemplateIndex(index)} > - setTemplateIndex(index)} - > - {templates.map((item, index) => ( - ({ - overflow: 'auto', - borderRadius: 1, - height: { xs: 220, sm: 320, md: 450 }, - backgroundImage: `url(${item.src.light})`, - backgroundSize: 'cover', - backgroundRepeat: 'no-repeat', - border: '1px solid', - borderColor: templateIndex === index ? 'primary.100' : 'divider', - boxShadow: `0px 2px 12px ${alpha(theme.palette.primary[200], 0.3)}`, - transition: '0.6s cubic-bezier(0.15, 0.3, 0.25, 1)', - transform: templateIndex !== index ? 'scale(0.92)' : 'scale(1)', - ...theme.applyDarkStyles({ - backgroundImage: `url(${item.src.dark})`, - borderColor: templateIndex === index ? 'primary.800' : 'divider', - boxShadow: `0px 2px 12px ${alpha(theme.palette.primary[900], 0.5)}`, + {templates.map((item, index) => ( + ({ + overflow: 'auto', + borderRadius: 1, + height: { xs: 220, sm: 320, md: 500 }, + backgroundImage: `url(${item.src.light})`, + backgroundSize: 'cover', + backgroundRepeat: 'no-repeat', + border: '1px solid', + borderColor: templateIndex === index ? 'primary.100' : 'divider', + boxShadow: + templateIndex === index + ? `0px 2px 12px ${alpha(theme.palette.primary[200], 0.3)}` + : undefined, + transition: '0.6s cubic-bezier(0.15, 0.3, 0.25, 1)', + transform: templateIndex !== index ? 'scale(0.92)' : 'scale(1)', + opacity: templateIndex === index ? 1 : 0.2, + ...theme.applyDarkStyles({ + backgroundImage: `url(${item.src.dark})`, + borderColor: templateIndex === index ? 'primary.900' : 'divider', + boxShadow: + templateIndex === index + ? `0px 2px 8px ${alpha(theme.palette.primary[900], 0.4)}` + : undefined, + }), + })} + > + ({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + flexDirection: 'column', + gap: 1, + transition: '0.2s', + position: 'absolute', + width: '100%', + height: '100%', + opacity: 0, + top: 0, + left: 0, + bgcolor: alpha(theme.palette.primary[50], 0.6), + backdropFilter: 'blur(4px)', + textDecoration: 'none', + '&:hover, &:focus': { + opacity: 1, + }, + ...theme.applyDarkStyles({ + bgcolor: alpha(theme.palette.primaryDark[900], 0.6), + }), }), - })} + ]} > - + Developed by {templates[templateIndex].author} + + + {templates[templateIndex].name} + + ({ display: 'flex', alignItems: 'center', - justifyContent: 'center', - flexDirection: 'column', - gap: 1, - transition: '0.2s', - position: 'absolute', - width: '100%', - height: '100%', - opacity: 0, - top: 0, - left: 0, - bgcolor: alpha(theme.palette.primary[50], 0.6), - backdropFilter: 'blur(4px)', - textDecoration: 'none', - '&:hover, &:focus': { - opacity: 1, - }, + gap: 0.5, + color: 'primary.500', ...theme.applyDarkStyles({ - bgcolor: alpha(theme.palette.primaryDark[900], 0.6), + color: 'primary.200', }), }), ]} > - ({ - color: 'text.primary', - ...theme.applyDarkStyles({ - color: '#FFF', - }), - }), - ]} - > - {templates[templateIndex].name} - - ({ - display: 'flex', - alignItems: 'center', - gap: 0.5, - color: 'primary.500', - ...theme.applyDarkStyles({ - color: 'primary.100', - }), - }), - ]} - > - Buy now - - - - - ))} - - {templates.length > 1 && ( - - setTemplateIndex((current) => Math.max(0, current - 1))} - sx={{ left: 0, transform: 'translate(-50%)', justifyContent: 'flex-end' }} - > - - - - setTemplateIndex((current) => Math.min(templates.length - 1, current + 1)) - } - sx={{ right: 0, transform: 'translate(50%)', justifyContent: 'flex-start' }} - > - - - - )} - - - + Buy now + + + + + ))} + + {templates.length > 1 && ( + + setTemplateIndex((current) => Math.max(0, current - 1))} + sx={{ left: 0, transform: 'translate(-50%)', justifyContent: 'flex-end' }} + > + + + + setTemplateIndex((current) => Math.min(templates.length - 1, current + 1)) + } + sx={{ right: 0, transform: 'translate(50%)', justifyContent: 'flex-start' }} + > + + + + )} + +
); } diff --git a/docs/src/components/productMaterial/MaterialTheming.tsx b/docs/src/components/productMaterial/MaterialTheming.tsx index 01079c893757c9..5324961df64cbb 100644 --- a/docs/src/components/productMaterial/MaterialTheming.tsx +++ b/docs/src/components/productMaterial/MaterialTheming.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles'; -import Grid from '@mui/material/Grid'; +import Grid from '@mui/material/Unstable_Grid2'; import Typography from '@mui/material/Typography'; import AutoAwesomeRounded from '@mui/icons-material/AutoAwesomeRounded'; import Section from 'docs/src/layouts/Section'; @@ -11,8 +11,8 @@ import Highlighter from 'docs/src/components/action/Highlighter'; import SvgMaterialDesign from 'docs/src/icons/SvgMaterialDesign'; import Frame from 'docs/src/components/action/Frame'; import PlayerCard from 'docs/src/components/showcase/PlayerCard'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; -import MarkdownElement from 'docs/src/components/markdown/MarkdownElement'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; +import { MarkdownElement } from '@mui/docs/MarkdownElement'; const code = ` - + - + - + specific use case } - description="A collection of 4.5 average rating templates, for multiple use cases, all powered by Material UI components and carefully curated by MUI's team. - " + description="The Material UI collection of templates offers an expanding list of use cases designed to support projects of various types." /> {DEMOS.map((name) => ( @@ -93,7 +92,7 @@ export default function TemplateDemo() { /> - + - - +
+ {templates[templateIndex].name} - - - {templateIndex + 1} / {templates.length} - - - + + Developed by {templates[templateIndex].author} + +
+ + {templateIndex + 1} / {templates.length} +
diff --git a/docs/src/components/productTemplate/TemplateHero.tsx b/docs/src/components/productTemplate/TemplateHero.tsx index aff549228dac2f..1cb0646dfcea50 100644 --- a/docs/src/components/productTemplate/TemplateHero.tsx +++ b/docs/src/components/productTemplate/TemplateHero.tsx @@ -35,10 +35,10 @@ export default function TemplateHero() { Templates - Fully built Material UI templates + Beautiful and fully built Material UI templates - A collection of 4.5 average rating templates, selected and curated by MUI's team of + A collection of 4.5 average rating templates, selected and curated by Material UI's maintainers to get your projects up and running today. -
- ); -} +export default CodeCopyButton; diff --git a/docs/src/modules/components/ComponentsApiContent.js b/docs/src/modules/components/ComponentsApiContent.js index eab0596c3c8c06..59d7e53c6073f6 100644 --- a/docs/src/modules/components/ComponentsApiContent.js +++ b/docs/src/modules/components/ComponentsApiContent.js @@ -5,7 +5,7 @@ import kebabCase from 'lodash/kebabCase'; import { useRouter } from 'next/router'; import { exactProp } from '@mui/utils'; import { useTranslate, useUserLanguage } from '@mui/docs/i18n'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; import MarkdownElement from 'docs/src/modules/components/MarkdownElement'; import PropertiesSection from 'docs/src/modules/components/ApiPage/sections/PropertiesSection'; import ClassesSection from 'docs/src/modules/components/ApiPage/sections/ClassesSection'; diff --git a/docs/src/modules/components/Demo.js b/docs/src/modules/components/Demo.js index ed82ae5d5aa386..5da994f1ecdfab 100644 --- a/docs/src/modules/components/Demo.js +++ b/docs/src/modules/components/Demo.js @@ -4,12 +4,14 @@ import { useRouter } from 'next/router'; import { debounce } from '@mui/material/utils'; import { alpha, styled } from '@mui/material/styles'; import { styled as joyStyled } from '@mui/joy/styles'; +import { Tabs } from '@mui/base/Tabs'; +import { TabPanel } from '@mui/base/TabPanel'; import { unstable_useId as useId } from '@mui/utils'; import IconButton from '@mui/material/IconButton'; import Box from '@mui/material/Box'; import Collapse from '@mui/material/Collapse'; import NoSsr from '@mui/material/NoSsr'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; import DemoSandbox from 'docs/src/modules/components/DemoSandbox'; import ReactRunner from 'docs/src/modules/components/ReactRunner'; import DemoEditor from 'docs/src/modules/components/DemoEditor'; @@ -21,8 +23,9 @@ import { useCodeStyling } from 'docs/src/modules/utils/codeStylingSolution'; import { CODE_VARIANTS, CODE_STYLING } from 'docs/src/modules/constants'; import { useUserLanguage, useTranslate } from '@mui/docs/i18n'; import stylingSolutionMapping from 'docs/src/modules/utils/stylingSolutionMapping'; -import { BrandingProvider, blue, blueDark, grey } from '@mui/docs/branding'; import DemoToolbarRoot from 'docs/src/modules/components/DemoToolbarRoot'; +import { BrandingProvider, blue, blueDark, grey } from '@mui/docs/branding'; +import { CodeTab, CodeTabList } from 'docs/src/modules/components/HighlightedCodeWithTabs'; /** * Removes leading spaces (indentation) present in the `.tsx` previews @@ -68,24 +71,31 @@ function useDemoData(codeVariant, demo, githubLocation, codeStyling) { } let codeOptions = {}; - if (codeStyling === CODE_STYLING.SYSTEM) { if (codeVariant === CODE_VARIANTS.TS && demo.rawTS) { codeOptions = { codeVariant: CODE_VARIANTS.TS, githubLocation: githubLocation.replace(/\.js$/, '.tsx'), raw: demo.rawTS, - Component: demo.tsx, + module: demo.moduleTS, + Component: demo.tsx ?? null, sourceLanguage: 'tsx', }; + if (demo.relativeModules) { + codeOptions.relativeModules = demo.relativeModules[CODE_VARIANTS.TS]; + } } else { codeOptions = { codeVariant: CODE_VARIANTS.JS, githubLocation, raw: demo.raw, + module: demo.module, Component: demo.js, sourceLanguage: 'jsx', }; + if (demo.relativeModules) { + codeOptions.relativeModules = demo.relativeModules[CODE_VARIANTS.JS]; + } } } else if (codeStyling === CODE_STYLING.TAILWIND) { if (codeVariant === CODE_VARIANTS.TS && demo.rawTailwindTS) { @@ -93,6 +103,7 @@ function useDemoData(codeVariant, demo, githubLocation, codeStyling) { codeVariant: CODE_VARIANTS.TS, githubLocation: githubLocation.replace(/\/system\/index\.js$/, '/tailwind/index.tsx'), raw: demo.rawTailwindTS, + module: demo.moduleTS, Component: demo.tsxTailwind, sourceLanguage: 'tsx', }; @@ -101,6 +112,7 @@ function useDemoData(codeVariant, demo, githubLocation, codeStyling) { codeVariant: CODE_VARIANTS.JS, githubLocation: githubLocation.replace(/\/system\/index\.js$/, '/tailwind/index.js'), raw: demo.rawTailwind ?? demo.raw, + module: demo.module, Component: demo.jsTailwind ?? demo.js, sourceLanguage: 'jsx', }; @@ -111,6 +123,7 @@ function useDemoData(codeVariant, demo, githubLocation, codeStyling) { codeVariant: CODE_VARIANTS.TS, githubLocation: githubLocation.replace(/\/system\/index\.js$/, '/css/index.tsx'), raw: demo.rawCSSTS, + module: demo.moduleTS, Component: demo.tsxCSS, sourceLanguage: 'tsx', }; @@ -119,6 +132,7 @@ function useDemoData(codeVariant, demo, githubLocation, codeStyling) { codeVariant: CODE_VARIANTS.JS, githubLocation: githubLocation.replace(/\/system\/index\.js$/, '/css/index.js'), raw: demo.rawCSS ?? demo.raw, + module: demo.module, Component: demo.jsCSS ?? demo.js, sourceLanguage: 'jsx', }; @@ -329,9 +343,12 @@ const DemoRootJoy = joyStyled('div', { const DemoCodeViewer = styled(HighlightedCode)(() => ({ '& pre': { margin: 0, + marginTop: -1, maxHeight: 'min(68vh, 1000px)', maxWidth: 'initial', borderRadius: 0, + borderBottomLeftRadius: 12, + borderBottomRightRadius: 12, }, '& .MuiCode-copy': { display: 'none', @@ -352,6 +369,20 @@ const InitialFocus = styled(IconButton)(({ theme }) => ({ pointerEvents: 'none', })); +const selectionOverride = (theme) => ({ + cursor: 'pointer', + '&.base--selected': { + color: (theme.vars || theme).palette.primary[700], + backgroundColor: (theme.vars || theme).palette.primary[50], + borderColor: (theme.vars || theme).palette.primary[200], + ...theme.applyDarkStyles({ + color: (theme.vars || theme).palette.primary[200], + backgroundColor: alpha((theme.vars || theme).palette.primary[900], 0.4), + borderColor: (theme.vars || theme).palette.primary[800], + }), + }, +}); + export default function Demo(props) { const { demo, demoOptions, disableAd, githubLocation, mode } = props; @@ -500,6 +531,32 @@ export default function Demo(props) { liveDemoActive, }); + const [activeTab, setActiveTab] = React.useState(0); + const handleTabChange = (event, newValue) => { + setActiveTab(newValue); + }; + const ownerState = { mounted: true, contained: true }; + + const tabs = React.useMemo(() => { + if (!demoData.relativeModules) { + return [{ module: demoData.module, raw: demoData.raw }]; + } + let demoModule = demoData.module; + if (codeVariant === CODE_VARIANTS.TS && demo.moduleTS) { + demoModule = + demo.moduleTS === demo.module ? demoData.module.replace(/\.js$/, '.tsx') : demo.moduleTS; + } + + return [{ module: demoModule, raw: demoData.raw }, ...demoData.relativeModules]; + }, [ + codeVariant, + demo.moduleTS, + demo.module, + demoData.module, + demoData.raw, + demoData.relativeModules, + ]); + return ( @@ -558,46 +615,67 @@ export default function Demo(props) { - - {/* A limitation from https://github.com/nihgwu/react-runner, + + {demoData.relativeModules && openDemoSource && !editorCode.isPreview ? ( + + {tabs.map((tab, index) => ( + + {tab.module} + + ))} + + ) : null} + + {/* A limitation from https://github.com/nihgwu/react-runner, we can't inject the `window` of the iframe so we need a disableLiveEdit option. */} - {demoOptions.disableLiveEdit ? ( - - ) : ( - { - setEditorCode({ - ...editorCode, - value, - }); - }} - onFocus={() => { - setLiveDemoActive(true); - }} - id={demoSourceId} - language={demoData.sourceLanguage} - copyButtonProps={{ - 'data-ga-event-category': codeOpen ? 'demo-expand' : 'demo', - 'data-ga-event-label': demo.gaLabel, - 'data-ga-event-action': 'copy-click', - }} - > - {debouncedError} - - )} - + {tabs.map((tab, index) => ( + + {demoOptions.disableLiveEdit || index > 0 ? ( + + ) : ( + { + setEditorCode({ + ...editorCode, + value, + }); + }} + onFocus={() => { + setLiveDemoActive(true); + }} + id={demoSourceId} + language={demoData.sourceLanguage} + copyButtonProps={{ + 'data-ga-event-category': codeOpen ? 'demo-expand' : 'demo', + 'data-ga-event-label': demo.gaLabel, + 'data-ga-event-action': 'copy-click', + }} + > + {debouncedError} + + )} + + ))} + + {adVisibility ? : null} )} diff --git a/docs/src/modules/components/DemoEditor.tsx b/docs/src/modules/components/DemoEditor.tsx index b73c500fae1727..bdee7f8daaa130 100644 --- a/docs/src/modules/components/DemoEditor.tsx +++ b/docs/src/modules/components/DemoEditor.tsx @@ -7,7 +7,7 @@ import prism from '@mui/internal-markdown/prism'; import MarkdownElement from 'docs/src/modules/components/MarkdownElement'; import CodeCopyButton from 'docs/src/modules/components/CodeCopyButton'; import { useTranslate } from '@mui/docs/i18n'; -import { useCodeCopy } from 'docs/src/modules/utils/CodeCopy'; +import { useCodeCopy } from '@mui/docs/CodeCopy'; import { blueDark } from '@mui/docs/branding'; const StyledMarkdownElement = styled(MarkdownElement)(({ theme }) => [ @@ -17,17 +17,20 @@ const StyledMarkdownElement = styled(MarkdownElement)(({ theme }) => [ overflow: 'auto', marginTop: -1, backgroundColor: 'hsl(210, 35%, 9%)', // a special, one-off, color tailored for the code blocks using MUI's branding theme blue palette as the starting point. It has a less saturaded color but still maintaining a bit of the blue tint. - border: `1px solid ${(theme.vars || theme).palette.divider}`, + border: 0, colorScheme: 'dark', '&:hover': { boxShadow: `0 0 0 3px ${alpha((theme.vars || theme).palette.primary[500], 0.5)}`, }, '&:focus-within': { - boxShadow: `0 0 0 2px ${alpha((theme.vars || theme).palette.primary[500], 0.5)}`, + boxShadow: `0 0 0 3px ${alpha((theme.vars || theme).palette.primary[500], 0.8)}`, }, [theme.breakpoints.up('sm')]: { borderRadius: '0 0 12px 12px', }, + ...theme.applyDarkStyles({ + border: `1px solid ${(theme.vars || theme).palette.divider}`, + }), }, '& pre': { // The scroll container needs to be the parent of the editor, overriding: @@ -39,11 +42,6 @@ const StyledMarkdownElement = styled(MarkdownElement)(({ theme }) => [ display: 'none', }, }, - theme.applyDarkStyles({ - '& .scrollContainer': { - borderColor: (theme.vars || theme).palette.divider, - }, - }), ]) as any; const StyledSimpleCodeEditor = styled(SimpleCodeEditor)(({ theme }) => ({ diff --git a/docs/src/modules/components/DemoToolbar.js b/docs/src/modules/components/DemoToolbar.js index bb057eb447e4a4..8a0e8fbe97a14f 100644 --- a/docs/src/modules/components/DemoToolbar.js +++ b/docs/src/modules/components/DemoToolbar.js @@ -8,7 +8,7 @@ import CheckIcon from '@mui/icons-material/Check'; import Fade from '@mui/material/Fade'; import MDButton from '@mui/material/Button'; import Box from '@mui/material/Box'; -import MDToggleButton, { toggleButtonClasses } from '@mui/material/ToggleButton'; +import MDToggleButton from '@mui/material/ToggleButton'; import MDToggleButtonGroup, { toggleButtonGroupClasses } from '@mui/material/ToggleButtonGroup'; import SvgIcon from '@mui/material/SvgIcon'; import Snackbar from '@mui/material/Snackbar'; @@ -69,23 +69,18 @@ const ToggleButtonGroup = styled(MDToggleButtonGroup)(({ theme }) => [ theme.unstable_sx({ [`& .${toggleButtonGroupClasses.grouped}`]: { '&:not(:first-of-type)': { - marginLeft: 0.8, - borderLeft: '1px solid', - borderLeftColor: 'divider', - borderTopLeftRadius: 999, - borderBottomLeftRadius: 999, + pr: '2px', // a nudge for optical alignment }, '&:not(:last-of-type)': { - borderTopRightRadius: 999, - borderBottomRightRadius: 999, + pl: '2px', // a nudge for optical alignment }, }, }), ]); const Button = styled(MDButton)(({ theme }) => ({ - height: 24, - padding: '5px 8px 6px 8px', // the one-off 5px is for visually centering the text on the button's container + height: 26, + padding: '6px 8px 8px 8px', flexShrink: 0, borderRadius: 999, border: '1px solid', @@ -130,29 +125,15 @@ const MenuItem = styled(MDMenuItem)(({ theme }) => ({ const ToggleButton = styled(MDToggleButton)(({ theme }) => [ theme.unstable_sx({ - padding: theme.spacing(0, 1, 0.1, 1), + height: 26, + width: 38, + p: 0, fontSize: theme.typography.pxToRem(13), - borderColor: 'grey.200', borderRadius: '999px', '&.Mui-disabled': { - opacity: 0.5, + opacity: 0.8, + cursor: 'not-allowed', }, - [`&.${toggleButtonClasses.selected}:hover`]: { - backgroundColor: theme.vars - ? `rgba(${theme.vars.palette.primary.mainChannel} / calc(${theme.vars.palette.action.selectedOpacity} + ${theme.vars.palette.action.hoverOpacity}))` - : alpha( - theme.palette.primary.main, - theme.palette.action.selectedOpacity + theme.palette.action.hoverOpacity, - ), - '@media (hover: none)': { - backgroundColor: theme.vars - ? `rgba(${theme.vars.palette.primary.mainChannel} / ${theme.vars.palette.action.selectedOpacity})` - : alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity), - }, - }, - }), - theme.applyDarkStyles({ - borderColor: theme.palette.primaryDark[700], }), ]); @@ -281,6 +262,31 @@ function useToolbar(controlRefs, options = {}) { }; } +function copyWithRelativeModules(raw, relativeModules) { + if (relativeModules) { + relativeModules.forEach(({ module, raw: content }) => { + // remove exports from relative module + content = content.replace(/export( )*(default)*( )*\w+;|export default|export/gm, ''); + // replace import statement with relative module content + // the module might be imported with or without extension, so we need to cover all cases + // E.g.: /import .* from '(.\/top100Films.js|.\/top100Films)';/ + const extensions = ['', '.js', '.jsx', '.ts', '.tsx', '.css', '.json']; + const patterns = extensions + .map((ext) => { + if (module.endsWith(ext)) { + return module.replace(ext, ''); + } + return ''; + }) + .filter(Boolean) + .join('|'); + const importPattern = new RegExp(`import .* from '(${patterns})';`); + raw = raw.replace(importPattern, content); + }); + } + return copy(raw); +} + export default function DemoToolbar(props) { const { codeOpen, @@ -332,9 +338,10 @@ export default function DemoToolbar(props) { const handleSnackbarClose = () => { setSnackbarOpen(false); }; + const handleCopyClick = async () => { try { - await copy(demoData.raw); + await copyWithRelativeModules(demoData.raw, demoData.relativeModules); setSnackbarMessage(t('copiedSource')); setSnackbarOpen(true); } finally { @@ -499,7 +506,7 @@ export default function DemoToolbar(props) { )} - + {hasNonSystemDemos && ( )} diff --git a/docs/src/modules/components/DemoToolbarRoot.ts b/docs/src/modules/components/DemoToolbarRoot.ts index 071aea7f1df146..8632ce1ad77bfa 100644 --- a/docs/src/modules/components/DemoToolbarRoot.ts +++ b/docs/src/modules/components/DemoToolbarRoot.ts @@ -12,6 +12,7 @@ const DemoToolbarRoot = styled('div', { display: 'none', [theme.breakpoints.up('sm')]: { top: 0, + maxHeight: 50, display: 'block', marginTop: demoOptions.bg === 'inline' ? theme.spacing(1) : -1, padding: theme.spacing(0.5, 1), diff --git a/docs/src/modules/components/HighlightedCode.js b/docs/src/modules/components/HighlightedCode.js index ca7a8458fa1034..16848d1f2cfac8 100644 --- a/docs/src/modules/components/HighlightedCode.js +++ b/docs/src/modules/components/HighlightedCode.js @@ -1,52 +1,5 @@ -import * as React from 'react'; -import PropTypes from 'prop-types'; -import prism from '@mui/internal-markdown/prism'; -import { NoSsr } from '@mui/base/NoSsr'; -import MarkdownElement from 'docs/src/modules/components/MarkdownElement'; -import CodeCopyButton from 'docs/src/modules/components/CodeCopyButton'; -import { useCodeCopy } from 'docs/src/modules/utils/CodeCopy'; - -const HighlightedCode = React.forwardRef(function HighlightedCode(props, ref) { - const { - copyButtonHidden = false, - copyButtonProps, - code, - language, - component: Component = MarkdownElement, - ...other - } = props; - const renderedCode = React.useMemo(() => { - return prism(code.trim(), language); - }, [code, language]); - const handlers = useCodeCopy(); - - return ( - -
- {copyButtonHidden ? null : ( - - - - )} -
-          
-        
-
-
- ); -}); - -HighlightedCode.propTypes = { - code: PropTypes.string.isRequired, - component: PropTypes.elementType, - copyButtonHidden: PropTypes.bool, - copyButtonProps: PropTypes.object, - language: PropTypes.string.isRequired, - sx: PropTypes.object, -}; +// Backwards compatibility for Toolpad and X. +// TODO: remove when Toolpad and X migrated to `@mui/docs/HighlightedCode` +import { HighlightedCode } from '@mui/docs/HighlightedCode'; export default HighlightedCode; diff --git a/docs/src/modules/components/HighlightedCode.test.js b/docs/src/modules/components/HighlightedCode.test.js index 05f7f1b627a523..60ccf9b7c04ff4 100644 --- a/docs/src/modules/components/HighlightedCode.test.js +++ b/docs/src/modules/components/HighlightedCode.test.js @@ -3,7 +3,7 @@ import { expect } from 'chai'; import { createRenderer } from '@mui-internal/test-utils'; import { ThemeProvider, createTheme } from '@mui/material/styles'; import { getDesignTokens } from '@mui/docs/branding'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; describe('HighlightedCode', () => { const { render } = createRenderer(); diff --git a/docs/src/modules/components/HighlightedCodeWithTabs.tsx b/docs/src/modules/components/HighlightedCodeWithTabs.tsx index 7372011ff47f06..27242449152c99 100644 --- a/docs/src/modules/components/HighlightedCodeWithTabs.tsx +++ b/docs/src/modules/components/HighlightedCodeWithTabs.tsx @@ -7,22 +7,35 @@ import { Tab as TabBase } from '@mui/base/Tab'; import useLocalStorageState from '@mui/utils/useLocalStorageState'; import HighlightedCode from './HighlightedCode'; -const TabList = styled(TabsListBase)(({ theme }) => ({ - padding: 6, +export const CodeTabList = styled(TabsListBase)<{ + ownerState: { mounted: boolean; contained?: boolean }; +}>(({ theme, ownerState }) => ({ + padding: ownerState?.contained ? theme.spacing(1.5, 1) : theme.spacing(1), display: 'flex', - border: '1px solid', - borderColor: (theme.vars || theme).palette.primaryDark[700], - backgroundColor: (theme.vars || theme).palette.primaryDark[900], - borderTopLeftRadius: (theme.vars || theme).shape.borderRadius, - borderTopRightRadius: (theme.vars || theme).shape.borderRadius, + gap: theme.spacing(0.5), + borderLeft: '1px solid', + borderRight: '1px solid', + borderTop: ownerState?.contained ? 'none' : '1px solid', + borderBottom: ownerState?.contained ? 'none' : '1px solid', + borderTopLeftRadius: ownerState?.contained ? 0 : (theme.vars || theme).shape.borderRadius, + borderTopRightRadius: ownerState?.contained ? 0 : (theme.vars || theme).shape.borderRadius, + borderColor: ownerState?.contained + ? (theme.vars || theme).palette.divider + : (theme.vars || theme).palette.primaryDark[700], + backgroundColor: ownerState?.contained + ? alpha(theme.palette.grey[50], 0.2) + : (theme.vars || theme).palette.primaryDark[900], ...theme.applyDarkStyles({ - backgroundColor: alpha(theme.palette.primaryDark[800], 0.5), + backgroundColor: alpha(theme.palette.primaryDark[800], 0.2), }), })); -const TabPanel = styled(TabPanelBase)<{ ownerState: { mounted: boolean } }>(({ ownerState }) => ({ +export const CodeTabPanel = styled(TabPanelBase)<{ + ownerState: { mounted: boolean; contained?: boolean }; +}>(({ ownerState }) => ({ + marginTop: ownerState?.contained ? -1 : 0, '& pre': { - marginTop: -1, + marginTop: ownerState?.contained ? 0 : -1, borderTopLeftRadius: 0, borderTopRightRadius: 0, '& code': { @@ -31,46 +44,59 @@ const TabPanel = styled(TabPanelBase)<{ ownerState: { mounted: boolean } }>(({ o }, })); -const Tab = styled(TabBase)<{ ownerState: { mounted: boolean } }>(({ theme, ownerState }) => - theme.unstable_sx({ - p: 0.8, - border: 'none', - bgcolor: 'transparent', - color: (theme.vars || theme).palette.grey[500], - fontSize: theme.typography.pxToRem(12), - fontWeight: theme.typography.fontWeightSemiBold, - fontFamily: theme.typography.fontFamilyCode, - outline: 'none', - minWidth: 52, - cursor: 'pointer', - borderRadius: '8px', - position: 'relative', - '&:not(:first-of-type)': { - marginLeft: 0.5, - }, - ...(ownerState.mounted && { - '&.base--selected': { - color: '#FFF', - '&::after': { - content: "''", - position: 'absolute', - left: 0, - bottom: '-6px', - height: 2, - width: '100%', - bgcolor: (theme.vars || theme).palette.primary.light, - }, +export const CodeTab = styled(TabBase)<{ ownerState: { mounted: boolean; contained?: boolean } }>( + ({ theme, ownerState }) => + theme.unstable_sx({ + height: 26, + p: '0 8px 2px 8px', + border: ownerState?.contained ? '1px solid transparent' : 'none', + bgcolor: 'transparent', + color: ownerState?.contained + ? (theme.vars || theme).palette.text.tertiary + : (theme.vars || theme).palette.grey[500], + fontSize: theme.typography.pxToRem(ownerState?.contained ? 13 : 12), + fontFamily: ownerState?.contained + ? theme.typography.fontFamily + : theme.typography.fontFamilyCode, + fontWeight: ownerState?.contained + ? theme.typography.fontWeightMedium + : theme.typography.fontWeightBold, + lineHeight: 1.2, + outline: 'none', + minWidth: 52, + cursor: 'pointer', + borderRadius: 99, + position: 'relative', + transition: ownerState?.contained ? 'background, color, 100ms ease' : 'unset', + '&:hover': { + backgroundColor: (theme.vars || theme).palette.divider, }, + '&:focus-visible': { + outline: '3px solid', + outlineOffset: '1px', + outlineColor: (theme.vars || theme).palette.primary.light, + }, + ...(!ownerState?.contained && { + '&:hover': { + backgroundColor: alpha(theme.palette.primaryDark[500], 0.5), + color: (theme.vars || theme).palette.grey[400], + }, + ...(ownerState.mounted && { + '&.base--selected': { + color: '#FFF', + '&::after': { + content: "''", + position: 'absolute', + left: 0, + bottom: '-8px', + height: 2, + width: '100%', + bgcolor: (theme.vars || theme).palette.primary.light, + }, + }, + }), + }), }), - '&:hover': { - backgroundColor: alpha(theme.palette.primaryDark[500], 0.5), - }, - '&:focus-visible': { - outline: '2px solid', - outlineOffset: '-2px', - outlineColor: (theme.vars || theme).palette.primary.light, - }, - }), ); type TabsConfig = { @@ -88,6 +114,8 @@ export default function HighlightedCodeWithTabs( const { tabs, storageKey } = props; const availableTabs = React.useMemo(() => tabs.map(({ tab }) => tab), [tabs]); const [activeTab, setActiveTab] = useLocalStorageState(storageKey ?? null, availableTabs[0]); + // During hydration, activeTab is null, default to first value. + const defaultizedActiveTab = activeTab ?? availableTabs[0]; const [mounted, setMounted] = React.useState(false); @@ -101,22 +129,22 @@ export default function HighlightedCodeWithTabs( const ownerState = { mounted }; return ( - - + + {tabs.map(({ tab }) => ( - + {tab} - + ))} - + {tabs.map(({ tab, language, code }) => ( - + - + ))} ); diff --git a/docs/src/modules/components/HooksApiContent.js b/docs/src/modules/components/HooksApiContent.js index acb36479c6dd62..cc330f3b22ec67 100644 --- a/docs/src/modules/components/HooksApiContent.js +++ b/docs/src/modules/components/HooksApiContent.js @@ -5,7 +5,7 @@ import kebabCase from 'lodash/kebabCase'; import { exactProp } from '@mui/utils'; import { useTranslate, useUserLanguage } from '@mui/docs/i18n'; import PropertiesSection from 'docs/src/modules/components/ApiPage/sections/PropertiesSection'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; import MarkdownElement from 'docs/src/modules/components/MarkdownElement'; import { DEFAULT_API_LAYOUT_STORAGE_KEYS } from 'docs/src/modules/components/ApiPage/sections/ToggleDisplayOption'; diff --git a/docs/src/modules/components/JoyThemeBuilder.tsx b/docs/src/modules/components/JoyThemeBuilder.tsx index fa274153726f15..7cceb465dcba4b 100644 --- a/docs/src/modules/components/JoyThemeBuilder.tsx +++ b/docs/src/modules/components/JoyThemeBuilder.tsx @@ -59,7 +59,7 @@ import Search from '@mui/icons-material/Search'; import DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined'; import DarkMode from '@mui/icons-material/DarkMode'; import LightMode from '@mui/icons-material/LightMode'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; import { BrandingProvider } from '@mui/docs/branding'; import codeSandbox from 'docs/src/modules/sandbox/CodeSandbox'; import sourceJoyTemplates, { TemplateData } from 'docs/src/modules/joy/sourceJoyTemplates'; diff --git a/docs/src/modules/components/JoyUsageDemo.tsx b/docs/src/modules/components/JoyUsageDemo.tsx index 8928e277af5ef7..787c5c22800aa4 100644 --- a/docs/src/modules/components/JoyUsageDemo.tsx +++ b/docs/src/modules/components/JoyUsageDemo.tsx @@ -19,7 +19,7 @@ import Sheet from '@mui/joy/Sheet'; import Switch from '@mui/joy/Switch'; import Typography from '@mui/joy/Typography'; import { BrandingProvider } from '@mui/docs/branding'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; const shallowEqual = (item1: { [k: string]: any }, item2: { [k: string]: any }) => { let equal = true; diff --git a/docs/src/modules/components/JoyVariablesDemo.tsx b/docs/src/modules/components/JoyVariablesDemo.tsx index 2d4392d3059bf3..fe4fb76e37d8ef 100644 --- a/docs/src/modules/components/JoyVariablesDemo.tsx +++ b/docs/src/modules/components/JoyVariablesDemo.tsx @@ -12,7 +12,7 @@ import FormHelperText from '@mui/joy/FormHelperText'; import Input, { inputClasses } from '@mui/joy/Input'; import ReplayRoundedIcon from '@mui/icons-material/ReplayRounded'; import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown'; -import HighlightedCode from 'docs/src/modules/components/HighlightedCode'; +import { HighlightedCode } from '@mui/docs/HighlightedCode'; import { BrandingProvider } from '@mui/docs/branding'; interface DataItem { diff --git a/docs/src/modules/components/MarkdownDocsV2.js b/docs/src/modules/components/MarkdownDocsV2.js index 8833babea4b493..cef3c473ccc059 100644 --- a/docs/src/modules/components/MarkdownDocsV2.js +++ b/docs/src/modules/components/MarkdownDocsV2.js @@ -81,7 +81,7 @@ export default function MarkdownDocsV2(props) { const localizedDoc = docs[userLanguage] || docs.en; // Generate the TOC based on the tab - const demosToc = localizedDoc.toc.filter((item) => item.text !== 'API'); + const demosToc = localizedDoc.toc; function createHookTocEntry(hookName, sectionName, hookProps = {}) { const hookPropToc = []; @@ -275,11 +275,7 @@ export default function MarkdownDocsV2(props) { {commonElements} {activeTab === '' && localizedDoc.rendered - // for the "hook only" edge case, for example Base UI autocomplete - .slice( - i, - localizedDoc.rendered.length - (localizedDoc.headers.components.length > 0 ? 1 : 0), - ) + .slice(i) .map((renderedMarkdownOrDemo, index) => ( ({ - ...lightTheme.typography.body1, - lineHeight: 1.6, // Increased compared to the 1.5 default to make the docs easier to read. - color: `var(--muidocs-palette-text-primary, ${lightTheme.palette.text.primary})`, - '& :focus-visible': { - outline: `3px solid ${alpha(lightTheme.palette.primary[500], 0.5)}`, - outlineOffset: 2, - }, - '& strong': { - color: `var(--muidocs-palette-text-primary, ${lightTheme.palette.text.primary})`, - }, - wordBreak: 'break-word', - '& pre': { - lineHeight: 1.5, // Developers like when the code is dense. - margin: theme.spacing(2, 'auto'), - padding: theme.spacing(2), - backgroundColor: 'hsl(210, 35%, 9%)', // a special, one-off, color tailored for the code blocks using MUI's branding theme blue palette as the starting point. It has a less saturaded color but still maintaining a bit of the blue tint. - color: 'hsl(60, 30%, 96%)', - colorScheme: 'dark', - borderRadius: `var(--muidocs-shape-borderRadius, ${ - theme.shape?.borderRadius ?? lightTheme.shape.borderRadius - }px)`, - border: '1px solid', - borderColor: `var(--muidocs-palette-primaryDark-700, ${lightTheme.palette.primaryDark[700]})`, - overflow: 'auto', - WebkitOverflowScrolling: 'touch', - fontSize: lightTheme.typography.pxToRem(13), - maxWidth: 'calc(100vw - 32px)', - maxHeight: '400px', - [lightTheme.breakpoints.up('md')]: { - maxWidth: 'calc(100vw - 32px - 16px)', - }, - }, - '& code': { - ...lightTheme.typography.body2, - fontFamily: lightTheme.typography.fontFamilyCode, - fontWeight: 400, - WebkitFontSmoothing: 'subpixel-antialiased', - }, - '& pre > code': { - // Reset for Safari - // https://github.com/necolas/normalize.css/blob/master/normalize.css#L102 - fontSize: 'inherit', - }, - // inline code block - '& :not(pre) > code': { - padding: '2px 4px', - color: `var(--muidocs-palette-text-primary, ${lightTheme.palette.text.primary})`, - backgroundColor: `var(--muidocs-palette-grey-50, ${lightTheme.palette.grey[50]})`, - border: '1px solid', - borderColor: `var(--muidocs-palette-grey-200, ${lightTheme.palette.grey[200]})`, - borderRadius: 6, - fontSize: lightTheme.typography.pxToRem(13), - direction: 'ltr /*! @noflip */', - boxDecorationBreak: 'clone', - }, - '& h1': { - ...lightTheme.typography.h3, - fontSize: lightTheme.typography.pxToRem(36), - fontFamily: `"General Sans", ${lightTheme.typography.fontFamilySystem}`, - margin: '10px 0', - color: `var(--muidocs-palette-primaryDark-900, ${lightTheme.palette.primaryDark[900]})`, - fontWeight: 600, - letterSpacing: -0.2, - }, - '& .description': { - ...lightTheme.typography.subtitle1, - fontWeight: 400, - margin: '0 0 24px', - }, - '& .component-tabs': { - margin: '0 0 40px', - }, - '& h2': { - ...lightTheme.typography.h5, - fontFamily: `"General Sans", ${lightTheme.typography.fontFamilySystem}`, - fontSize: theme.typography.pxToRem(26), - fontWeight: lightTheme.typography.fontWeightSemiBold, - color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, - margin: '40px 0 4px', - }, - '& h3': { - ...lightTheme.typography.h6, - fontFamily: `"General Sans", ${lightTheme.typography.fontFamilySystem}`, - fontSize: theme.typography.pxToRem(20), - fontWeight: lightTheme.typography.fontWeightSemiBold, - color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, - margin: '24px 0 4px', - }, - '& h4': { - ...lightTheme.typography.subtitle1, - fontFamily: `"General Sans", ${lightTheme.typography.fontFamilySystem}`, - fontWeight: lightTheme.typography.fontWeightSemiBold, - color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, - margin: '20px 0 6px', - }, - '& h5': { - ...lightTheme.typography.subtitle2, - fontFamily: `"General Sans", ${lightTheme.typography.fontFamilySystem}`, - fontWeight: lightTheme.typography.fontWeightSemiBold, - color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, - margin: '20px 0 8px', - }, - '& p': { - marginTop: 0, - marginBottom: 16, - color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, - }, - '& ul, & ol': { - paddingLeft: 30, - marginTop: 0, - marginBottom: 16, - '& ul, & ol': { - marginBottom: 6, - }, - }, - '& h1, & h2, & h3, & h4': { - display: 'flex', - alignItems: 'center', - gap: 6, - '& code': { - fontSize: 'inherit', - lineHeight: 'inherit', - // Remove scroll on small screens. - wordBreak: 'break-all', - }, - '& .title-link-to-anchor': { - color: 'inherit', - textDecoration: 'none', - position: 'relative', - display: 'flex', - alignItems: 'center', - }, - '& .anchor-icon': { - // To prevent the link to get the focus. - display: 'inline-flex', - alignItems: 'center', - visibility: 'hidden', - }, - '& a:not(.title-link-to-anchor):hover': { - color: 'currentColor', - border: 'none', - boxShadow: '0 1px 0 0 currentColor', - textDecoration: 'none', - }, - '& .anchor-icon, & .comment-link': { - padding: 0, - cursor: 'pointer', - alignItems: 'center', - justifyContent: 'center', - flexShrink: 0, - textAlign: 'center', - marginLeft: 8, - height: 26, - width: 26, - backgroundColor: `var(--muidocs-palette-primary-50, ${lightTheme.palette.grey[50]})`, - color: `var(--muidocs-palette-grey-600, ${lightTheme.palette.grey[600]})`, - border: '1px solid', - borderColor: `var(--muidocs-palette-divider, ${lightTheme.palette.divider})`, - borderRadius: 8, - '&:hover': { - backgroundColor: alpha(lightTheme.palette.primary[100], 0.4), - borderColor: `var(--muidocs-palette-primary-100, ${lightTheme.palette.primary[100]})`, - color: `var(--muidocs-palette-primary-main, ${lightTheme.palette.primary.main})`, - }, - '& svg': { - height: 14, - width: 14, - fill: 'currentColor', - pointerEvents: 'none', - verticalAlign: 'middle', - }, - }, - '&:hover .anchor-icon': { - visibility: 'visible', - }, - '& .comment-link': { - display: 'none', // So we can have the comment button opt-in. - marginLeft: 'auto', - transition: theme.transitions.create('opacity', { - duration: theme.transitions.duration.shortest, - }), - '& svg': { - fill: 'currentColor', - marginRight: 1.5, - }, - }, - }, - '& h1 code, & h2 code, & h3 code': { - color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, - }, - '& h1 code': { - fontWeight: lightTheme.typography.fontWeightSemiBold, - }, - '& h2 code': { - fontSize: lightTheme.typography.pxToRem(24), - fontWeight: lightTheme.typography.fontWeightSemiBold, - }, - '& h3 code': { - fontSize: lightTheme.typography.pxToRem(18), - }, - '& table': { - // Trade display table for scroll overflow - display: 'block', - wordBreak: 'normal', - overflowX: 'auto', - WebkitOverflowScrolling: 'touch', - borderCollapse: 'collapse', - marginBottom: '20px', - borderSpacing: 0, - '& .prop-name, & .prop-type, & .prop-default, & .slot-name, & .slot-defaultClass, & .slot-default': - { - fontWeight: 400, - fontFamily: lightTheme.typography.fontFamilyCode, - WebkitFontSmoothing: 'subpixel-antialiased', - fontSize: lightTheme.typography.pxToRem(13), - }, - '& .required': { - color: '#006500', - }, - '& .optional': { - color: '#45529f', - }, - '& .prop-type, & .slot-defaultClass': { - color: '#932981', - }, - '& .prop-default, & .slot-default': { - borderBottom: `1px dotted var(--muidocs-palette-divider, ${lightTheme.palette.divider})`, - }, - }, - '& td': { - ...theme.typography.body2, - borderBottom: `1px solid var(--muidocs-palette-divider, ${lightTheme.palette.divider})`, - paddingRight: 20, - paddingTop: 16, - paddingBottom: 16, - color: `var(--muidocs-palette-text-secondary, ${lightTheme.palette.text.secondary})`, - }, - '& td code': { - lineHeight: 1.6, - }, - '& th': { - fontSize: theme.typography.pxToRem(14), - lineHeight: theme.typography.pxToRem(24), - fontWeight: 500, - color: `var(--muidocs-palette-text-primary, ${lightTheme.palette.text.primary})`, - whiteSpace: 'pre', - borderBottom: `1px solid var(--muidocs-palette-divider, ${lightTheme.palette.divider})`, - paddingRight: 20, - paddingTop: 12, - paddingBottom: 12, - }, - '& blockquote': { - position: 'relative', - padding: '0 16px', - margin: 0, - borderLeft: '1.5px solid', - borderColor: `var(--muidocs-palette-grey-200, ${lightTheme.palette.grey[200]})`, - '& p': { - fontSize: theme.typography.pxToRem(12.5), - fontFamily: lightTheme.typography.fontFamilyCode, - fontWeight: lightTheme.typography.fontWeightMedium, - lineHeight: theme.typography.pxToRem(24), - textIndent: 20, - }, - '&::before': { - position: 'absolute', - // eslint-disable-next-line material-ui/straight-quotes - content: '"“"', - color: `var(--muidocs-palette-grey-300, ${lightTheme.palette.grey[300]})`, - fontSize: '2.5rem', - top: 8, - marginLeft: -6, - lineHeight: 0.5, - }, - }, - '& .MuiCallout-root': { - display: 'flex', - gap: 12, - padding: '16px', - margin: '16px 0', - border: '1px solid', - color: `var(--muidocs-palette-text-secondary, ${lightTheme.palette.text.secondary})`, - borderColor: `var(--muidocs-palette-grey-100, ${lightTheme.palette.grey[100]})`, - borderRadius: `var(--muidocs-shape-borderRadius, ${ - theme.shape?.borderRadius ?? lightTheme.shape.borderRadius - }px)`, - '& > code': { - height: 'fit-content', - backgroundColor: `var(--muidocs-palette-grey-100, ${lightTheme.palette.grey[100]})`, - borderColor: `var(--muidocs-palette-grey-300, ${lightTheme.palette.grey[300]})`, - }, - '& .MuiCallout-content': { - minWidth: 0, // Allows content to shrink. Useful when callout contains code block - flexGrow: 1, - '& > p:last-child, & > ul:last-child': { - // Avoid margin on last child - marginBottom: 0, - }, - '& .MuiCode-root': { - '& > pre': { - margin: 0, - marginTop: 4, - }, - }, - '& > ul': { - // Because of the gap left by the icon, we visually need less padding - paddingLeft: 22, - }, - }, - '& > svg': { - marginTop: 2, - width: 20, - height: 20, - flexShrink: 0, - }, - '& > ul, & > p': { - '&:last-child': { - margin: 0, - }, - }, - '& ul, li, p': { - color: 'inherit', - }, - '&.MuiCallout-error': { - color: `var(--muidocs-palette-error-900, ${lightTheme.palette.error[900]})`, - backgroundColor: `var(--muidocs-palette-error-50, ${lightTheme.palette.error[50]})`, - borderColor: `var(--muidocs-palette-error-100, ${lightTheme.palette.error[100]})`, - '& strong': { - color: `var(--muidocs-palette-error-800, ${lightTheme.palette.error[800]})`, - }, - '& > svg': { - fill: `var(--muidocs-palette-error-500, ${lightTheme.palette.error[600]})`, - }, - '& a': { - color: `var(--muidocs-palette-error-800, ${lightTheme.palette.error[800]})`, - textDecorationColor: alpha(lightTheme.palette.error.main, 0.4), - '&:hover': { - textDecorationColor: 'inherit', - }, - }, - }, - '&.MuiCallout-info': { - color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, - backgroundColor: `var(--muidocs-palette-grey-50, ${lightTheme.palette.grey[50]})`, - borderColor: `var(--muidocs-palette-grey-100, ${lightTheme.palette.grey[100]})`, - '& strong': { - color: `var(--muidocs-palette-primary-800, ${lightTheme.palette.primary[800]})`, - }, - '& > svg': { - fill: `var(--muidocs-palette-grey-600, ${lightTheme.palette.grey[600]})`, - }, - }, - '&.MuiCallout-success': { - color: `var(--muidocs-palette-success-900, ${lightTheme.palette.success[900]})`, - backgroundColor: `var(--muidocs-palette-success-50, ${lightTheme.palette.success[50]})`, - borderColor: `var(--muidocs-palette-success-100, ${lightTheme.palette.success[100]})`, - '& strong': { - color: `var(--muidocs-palette-success-900, ${lightTheme.palette.success[900]})`, - }, - '& > svg': { - fill: `var(--muidocs-palette-success-600, ${lightTheme.palette.success[600]})`, - }, - '& a': { - color: `var(--muidocs-palette-success-900, ${lightTheme.palette.success[900]})`, - textDecorationColor: alpha(lightTheme.palette.success.main, 0.4), - '&:hover': { - textDecorationColor: 'inherit', - }, - }, - }, - '&.MuiCallout-warning': { - color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, - backgroundColor: alpha(lightTheme.palette.warning[50], 0.5), - borderColor: alpha(lightTheme.palette.warning[700], 0.15), - '& strong': { - color: `var(--muidocs-palette-warning-800, ${lightTheme.palette.warning[800]})`, - }, - '& > svg': { - fill: `var(--muidocs-palette-warning-600, ${lightTheme.palette.warning[600]})`, - }, - '& a': { - color: `var(--muidocs-palette-warning-800, ${lightTheme.palette.warning[800]})`, - textDecorationColor: alpha(lightTheme.palette.warning.main, 0.4), - '&:hover': { - textDecorationColor: 'inherit', - }, - }, - }, - }, - '& a[target="_blank"]::after': { - content: '""', - maskImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' focusable='false' aria-hidden='true' viewBox='0 0 24 24' fill='currentColor'%3E%3Cpath d='M6 6v2h8.59L5 17.59 6.41 19 16 9.41V18h2V6z'%3E%3C/path%3E%3C/svg%3E")`, - display: 'inline-flex', - width: '1em', - height: '1em', - color: 'inherit', - backgroundColor: 'currentColor', - transform: 'translate(0, 2px)', - transition: 'transform 0.3s cubic-bezier(0.1, 0.8, 0.3, 1)', // bounce effect - opacity: 0.8, - }, - '& a[target="_blank"]:hover::after': { - opacity: 1, - transform: 'translate(1px, 0)', - }, - '& a.remove-link-arrow::after': { - // Allows to remove link arrows for images - display: 'none', - }, - '& .Ad-root a::after': { - // Remove link arrow for ads - display: 'none', - }, - '& a:not(.title-link-to-anchor), & a:not(.title-link-to-anchor) code': { - // Style taken from the Link component - color: `var(--muidocs-palette-primary-600, ${lightTheme.palette.primary[600]})`, - fontWeight: theme.typography.fontWeightMedium, - textDecoration: 'underline', - textDecorationColor: alpha(lightTheme.palette.primary.main, 0.4), - '&:hover': { - textDecorationColor: 'inherit', - }, - }, - '& a:not(.title-link-to-anchor) code': { - color: darken(lightTheme.palette.primary.main, 0.2), - }, - '& img, & video': { - // Use !important so that inline style on or
- {stableSort( - appList.filter((item) => item[sortFunctionName] !== undefined), - sortFunction, - ).map((app) => ( - - {app.image ? ( - ({ - height: '100%', - display: 'flex', - flexDirection: 'column', - p: 2, - gap: 2, - borderRadius: 1, - backgroundColor: `${alpha(theme.palette.grey[50], 0.3)}`, - borderColor: 'divider', - ...theme.applyDarkStyles({ - backgroundColor: `${alpha(theme.palette.primaryDark[700], 0.2)}`, + {appList + .filter((item) => item[sortFunctionName] !== undefined) + .sort(sortFunction) + .map((app) => ( + + {app.image ? ( + ({ + height: '100%', + display: 'flex', + flexDirection: 'column', + p: 2, + gap: 2, + borderRadius: 1, + backgroundColor: `${alpha(theme.palette.grey[50], 0.3)}`, borderColor: 'divider', - }), - })} - > - - ({ - height: 'auto', - borderRadius: '6px', - bgcolor: 'currentColor', - border: '1px solid', + ...theme.applyDarkStyles({ + backgroundColor: `${alpha(theme.palette.primaryDark[700], 0.2)}`, borderColor: 'divider', - color: 'grey.100', - ...theme.applyDarkStyles({ - color: 'primaryDark.900', - }), - })} - /> - - - - {app.title} - {app.source ? ( - - - - ) : null} - - - {app.description} - - - - {app.dateAdded} - - - - ) : ( - - {t('visit')} - - )} - - ))} + }), + })} + > + + ({ + height: 'auto', + borderRadius: '6px', + bgcolor: 'currentColor', + border: '1px solid', + borderColor: 'divider', + color: 'grey.100', + ...theme.applyDarkStyles({ + color: 'primaryDark.900', + }), + })} + /> + + + + {app.title} + {app.source ? ( + + + + ) : null} + + + {app.description} + + + + {app.dateAdded} + + + + ) : ( + + {t('visit')} + + )} + + ))} ); diff --git a/docs/src/modules/components/RichMarkdownElement.js b/docs/src/modules/components/RichMarkdownElement.js index 449b1df5adb6a9..b41bf70bcdd5de 100644 --- a/docs/src/modules/components/RichMarkdownElement.js +++ b/docs/src/modules/components/RichMarkdownElement.js @@ -113,7 +113,9 @@ export default function RichMarkdownElement(props) { tailwindJsxPreview: demo.tailwindJsxPreview, cssJsxPreview: demo.cssJsxPreview, rawTS: demo.rawTS, - tsx: demoComponents[demo.moduleTS] ?? null, + module: demo.module, + moduleTS: demo.moduleTS, + tsx: demoComponents[demo.moduleTS] ?? noComponent(demo.moduleTS), rawTailwind: demo.rawTailwind, rawTailwindTS: demo.rawTailwindTS, jsTailwind: demoComponents[demo.moduleTailwind] ?? null, @@ -123,6 +125,7 @@ export default function RichMarkdownElement(props) { jsCSS: demoComponents[demo.moduleCSS] ?? null, tsxCSS: demoComponents[demo.moduleTSCSS] ?? null, gaLabel: fileNameWithLocation.replace(/^\/docs\/data\//, ''), + relativeModules: demo.relativeModules, }} disableAd={disableAd} demoOptions={renderedMarkdownOrDemo} diff --git a/docs/src/modules/utils/CodeCopy.tsx b/docs/src/modules/utils/CodeCopy.tsx index 68bd9de869c65a..a5f38002898f65 100644 --- a/docs/src/modules/utils/CodeCopy.tsx +++ b/docs/src/modules/utils/CodeCopy.tsx @@ -1,199 +1,4 @@ -import * as React from 'react'; -import copy from 'clipboard-copy'; -import { useRouter } from 'next/router'; +// Backwards compatibility for Toolpad and X. +// TODO: remove when Toolpad and X migrated to `@mui/docs/CodeCopy` -const CodeBlockContext = React.createContext>({ - current: null, -}); - -/** - * How to use: spread the handlers to the .MuiCode-root - * - * The html structure should be: - *
- *
...
- * - *
- */ -export function useCodeCopy(): any { - const rootNode = React.useContext(CodeBlockContext); - return { - onMouseEnter: (event: React.MouseEvent) => { - rootNode.current = event.currentTarget as HTMLDivElement; - }, - onMouseLeave: (event: React.MouseEvent) => { - if (rootNode.current === event.currentTarget) { - (rootNode.current.querySelector('.MuiCode-copy') as null | HTMLButtonElement)?.blur(); - rootNode.current = null; - } - }, - onFocus: (event: React.MouseEvent) => { - rootNode.current = event.currentTarget as HTMLDivElement; - }, - onBlur: (event: React.FocusEvent) => { - if (rootNode.current === event.currentTarget) { - rootNode.current = null; - } - }, - }; -} - -function InitCodeCopy() { - const rootNode = React.useContext(CodeBlockContext); - const router = useRouter(); - React.useEffect(() => { - let key = 'Ctrl + '; - if (typeof window !== 'undefined') { - const macOS = window.navigator.platform.toUpperCase().indexOf('MAC') >= 0; - if (macOS) { - key = '⌘'; - } - } - const codeRoots = document.getElementsByClassName( - 'MuiCode-root', - ) as HTMLCollectionOf; - - if (codeRoots !== null) { - const listeners: Array<() => void> = []; - Array.from(codeRoots).forEach((elm) => { - const handleMouseEnter = () => { - rootNode.current = elm; - }; - - elm.addEventListener('mouseenter', handleMouseEnter); - listeners.push(() => elm.removeEventListener('mouseenter', handleMouseEnter)); - - const handleMouseLeave = () => { - if (rootNode.current === elm) { - (rootNode.current.querySelector('.MuiCode-copy') as null | HTMLButtonElement)?.blur(); - rootNode.current = null; - } - }; - elm.addEventListener('mouseleave', handleMouseLeave); - listeners.push(() => elm.removeEventListener('mouseleave', handleMouseLeave)); - - const handleFocusin = () => { - // use `focusin` because it bubbles from the copy button - rootNode.current = elm; - }; - elm.addEventListener('focusin', handleFocusin); - listeners.push(() => elm.removeEventListener('focusin', handleFocusin)); - - const handleFocusout = () => { - // use `focusout` because it bubbles from the copy button - if (rootNode.current === elm) { - rootNode.current = null; - } - }; - elm.addEventListener('focusout', handleFocusout); - listeners.push(() => elm.removeEventListener('focusout', handleFocusout)); - - async function handleClick(event: MouseEvent) { - const trigger = event.currentTarget as HTMLButtonElement; - const pre = (event.currentTarget as Element)?.previousElementSibling as Element; - const textNode = trigger.childNodes[0]; - textNode.nodeValue = textNode.textContent?.replace('Copy', 'Copied') || null; - trigger.dataset.copied = 'true'; - setTimeout(() => { - if (trigger) { - textNode.nodeValue = textNode.textContent?.replace('Copied', 'Copy') || null; - delete trigger.dataset.copied; - } - }, 2000); - try { - if (pre.textContent) { - await copy(pre.textContent); - } - // eslint-disable-next-line no-empty - } catch (error) {} - } - - const btn = elm.querySelector('.MuiCode-copy') as HTMLButtonElement | null; - if (btn) { - const keyNode = btn.querySelector('.MuiCode-copyKeypress')?.childNodes[1]; - if (!keyNode) { - // skip the logic if the btn is not generated from the markdown. - return; - } - keyNode.textContent = keyNode?.textContent?.replace('$key', key) || null; - btn.addEventListener('click', handleClick); - listeners.push(() => btn.removeEventListener('click', handleClick)); - } - }); - - return () => { - listeners.forEach((removeEventListener) => { - removeEventListener(); - }); - }; - } - - return undefined; - }, [rootNode, router.pathname]); - return null; -} - -function hasNativeSelection(element: HTMLTextAreaElement) { - if (window.getSelection()?.toString()) { - return true; - } - - // window.getSelection() returns an empty string in Firefox for selections inside a form element. - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=85686. - // Instead, we can use element.selectionStart that is only defined on form elements. - if (element && (element.selectionEnd || 0) - (element.selectionStart || 0) > 0) { - return true; - } - - return false; -} - -interface CodeCopyProviderProps { - children: React.ReactNode; -} - -/** - * Place at the page level. It will check the keydown event and try to initiate copy click if rootNode exist. - * Any code block inside the tree can set the rootNode when mouse enter to leverage keyboard copy. - */ -export function CodeCopyProvider({ children }: CodeCopyProviderProps) { - const rootNode = React.useRef(null); - React.useEffect(() => { - document.addEventListener('keydown', (event) => { - if (!rootNode.current) { - return; - } - - // Skip if user is highlighting a text. - if (hasNativeSelection(event.target as HTMLTextAreaElement)) { - return; - } - - // Skip if it's not a copy keyboard event - if ( - !( - (event.ctrlKey || event.metaKey) && - event.key.toLowerCase() === 'c' && - !event.shiftKey && - !event.altKey - ) - ) { - return; - } - - const copyBtn = rootNode.current.querySelector('.MuiCode-copy') as HTMLButtonElement; - const initialEventAction = copyBtn.getAttribute('data-ga-event-action'); - // update the 'data-ga-event-action' on the button to track keyboard interaction - copyBtn.dataset.gaEventAction = - initialEventAction?.replace('click', 'keyboard') || 'copy-keyboard'; - copyBtn.click(); // let the GA setup in GoogleAnalytics.js do the job - copyBtn.dataset.gaEventAction = initialEventAction!; // reset the 'data-ga-event-action' back to initial - }); - }, []); - return ( - - - {children} - - ); -} +export * from '@mui/docs/CodeCopy'; diff --git a/docs/src/modules/utils/useClipboardCopy.ts b/docs/src/modules/utils/useClipboardCopy.ts index dd0b3b618b8e3e..817efb527c4c30 100644 --- a/docs/src/modules/utils/useClipboardCopy.ts +++ b/docs/src/modules/utils/useClipboardCopy.ts @@ -1,32 +1,5 @@ -import * as React from 'react'; -import clipboardCopy from 'clipboard-copy'; +// Backwards compatibility for Toolpad and X. +// TODO: remove when Toolpad and X migrated to `@mui/docs/CodeCopy` +import { useClipboardCopy } from '@mui/docs/CodeCopy'; -export default function useClipboardCopy() { - const [isCopied, setIsCopied] = React.useState(false); - const timeout = React.useRef>(); - const mounted = React.useRef(false); - - React.useEffect(() => { - mounted.current = true; - return () => { - mounted.current = false; - }; - }, []); - - const copy = async (text: string) => { - try { - setIsCopied(true); - clearTimeout(timeout.current); - timeout.current = setTimeout(() => { - if (mounted) { - setIsCopied(false); - } - }, 1200); - await clipboardCopy(text); - } catch (error) { - // ignore error - } - }; - - return { copy, isCopied }; -} +export default useClipboardCopy; diff --git a/netlify/edge-functions/og-image.tsx b/netlify/edge-functions/og-image.tsx index 43c6eab58a42e7..d1c4a05a055d30 100644 --- a/netlify/edge-functions/og-image.tsx +++ b/netlify/edge-functions/og-image.tsx @@ -78,6 +78,7 @@ export default async function handler(req: Request) { fontSize: '24px', fontWeight: 600, lineHeight: '40px', + letterSpacing: 1, color: '#007FFF', }} > @@ -101,8 +102,8 @@ export default async function handler(req: Request) { fontFamily: 'General Sans', fontStyle: 'normal', fontWeight: 600, - fontSize: '48px', - lineHeight: '57px', + fontSize: '56px', + lineHeight: '72px', color: '#0B0D0E', }} > @@ -130,10 +131,10 @@ export default async function handler(req: Request) { style={{ fontFamily: 'IBM Plex Sans', fontSize: '28px', - fontWeight: 600, - color: '#303740', + fontWeight: 500, + color: '#000', lineHeight: '50px', - marginTop: 12, + marginTop: 8, marginBottom: 0, marginLeft: 0, marginRight: 0, @@ -163,25 +164,25 @@ export default async function handler(req: Request) { display: 'flex', flexDirection: 'row', flexWrap: 'wrap', - marginBottom: 20, marginRight: 40, }} >
@@ -196,13 +197,12 @@ export default async function handler(req: Request) { style={{ fontFamily: 'IBM Plex Sans', fontSize: '26px', - fontWeight: '600', lineHeight: '40px', textAlign: 'left', color: '#101418', }} > - {name} + {name} a.arrayBuffer(), ), - weight: 600, + weight: 500, style: 'normal', }, { diff --git a/package.json b/package.json index 64b729f294cc42..cd4682f5879fcf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mui/monorepo", - "version": "6.0.0-alpha.2", + "version": "6.0.0-alpha.3", "private": true, "scripts": { "preinstall": "npx only-allow pnpm", @@ -98,7 +98,6 @@ "@babel/plugin-proposal-object-rest-spread": "^7.20.7", "@babel/plugin-proposal-private-methods": "^7.18.6", "@babel/plugin-proposal-private-property-in-object": "^7.21.11", - "@babel/plugin-transform-object-assign": "^7.24.1", "@babel/plugin-transform-react-constant-elements": "^7.24.1", "@babel/plugin-transform-runtime": "^7.24.3", "@babel/preset-env": "^7.24.4", diff --git a/packages-internal/docs-utils/package.json b/packages-internal/docs-utils/package.json index ad899d5b59ee0d..a5ab0c508a862d 100644 --- a/packages-internal/docs-utils/package.json +++ b/packages-internal/docs-utils/package.json @@ -1,6 +1,6 @@ { "name": "@mui/internal-docs-utils", - "version": "1.0.5", + "version": "1.0.6", "author": "MUI Team", "description": "Utilities for MUI docs. This is an internal package not meant for general use.", "main": "./build/index.js", diff --git a/packages-internal/scripts/package.json b/packages-internal/scripts/package.json index 76070d91afba5d..f8459dc41fc169 100644 --- a/packages-internal/scripts/package.json +++ b/packages-internal/scripts/package.json @@ -1,6 +1,6 @@ { "name": "@mui/internal-scripts", - "version": "1.0.5", + "version": "1.0.6", "author": "MUI Team", "description": "Utilities supporting MUI libraries build and docs generation. This is an internal package not meant for general use.", "main": "build/index.js", diff --git a/packages/markdown/loader.js b/packages/markdown/loader.js index 2c70b31176dabc..e9bacef953147d 100644 --- a/packages/markdown/loader.js +++ b/packages/markdown/loader.js @@ -1,4 +1,4 @@ -const { promises: fs, readdirSync } = require('fs'); +const { promises: fs, readdirSync, statSync } = require('fs'); const path = require('path'); const prepareMarkdown = require('./prepareMarkdown'); const extractImports = require('./extractImports'); @@ -127,6 +127,7 @@ module.exports = async function demoLoader() { const demoModuleIDs = new Set(); const componentModuleIDs = new Set(); const nonEditableDemos = new Set(); + const relativeModules = new Map(); const demoNames = Array.from( new Set( docs.en.rendered @@ -142,6 +143,63 @@ module.exports = async function demoLoader() { ), ); + /** + * @param {*} demoName + * @param {*} moduleFilepath + * @param {*} variant + * @param {*} importModuleID + * @example detectRelativeImports('ComboBox.js', '', JS', './top100Films') => relativeModules.set('ComboBox.js', new Map([['./top100Films.js', ['JS']]])) + */ + function detectRelativeImports(demoName, moduleFilepath, variant, importModuleID) { + if (importModuleID.startsWith('.')) { + let relativeModuleFilename = importModuleID; + const demoMap = relativeModules.get(demoName); + // If the moduleID does not end with an extension, or ends with an unsupported extension (e.g. ".styling") we need to resolve it + // Fastest way to get a file extension, see: https://stackoverflow.com/a/12900504/ + const importType = importModuleID.slice( + (Math.max(0, importModuleID.lastIndexOf('.')) || Infinity) + 1, + ); + const supportedTypes = ['js', 'jsx', 'ts', 'tsx', 'css', 'json']; + if (!importType || !supportedTypes.includes(importType)) { + // If the demo is a JS demo, we can assume that the relative import is either + // a `.js` or a `.jsx` file, with `.js` taking precedence over `.jsx` + // likewise for TS demos, with `.ts` taking precedence over `.tsx` + const extensions = + variant === 'JS' ? ['.js', '.jsx', '.ts', '.tsx'] : ['.ts', '.tsx', '.js', '.jsx']; + const extension = extensions.find((ext) => { + try { + return statSync(path.join(moduleFilepath, '..', `${importModuleID}${ext}`)); + } catch (error) { + // If the file does not exist, we return false and continue to the next extension + return false; + } + }); + if (!extension) { + throw new Error( + [ + `You are trying to import a module "${importModuleID}" in the demo "${demoName}" that could not be resolved.`, + `Please make sure that one of the following file exists:`, + ...extensions.map((ext) => `- ${importModuleID}${ext}`), + ].join('\n'), + ); + } else { + relativeModuleFilename = `${importModuleID}${extension}`; + } + } + + if (!demoMap) { + relativeModules.set(demoName, new Map([[relativeModuleFilename, [variant]]])); + } else { + const variantArray = demoMap.get(relativeModuleFilename); + if (variantArray) { + variantArray.push(variant); + } else { + demoMap.set(relativeModuleFilename, [variant]); + } + } + } + } + await Promise.all( demoNames.map(async (demoName) => { const multipleDemoVersionsUsed = !demoName.endsWith('.js'); @@ -168,11 +226,14 @@ module.exports = async function demoLoader() { raw: await fs.readFile(moduleFilepath, { encoding: 'utf8' }), }; demoModuleIDs.add(moduleID); + // Skip non-editable demos if (!nonEditableDemos.has(demoName)) { - extractImports(demos[demoName].raw).forEach((importModuleID) => - importedModuleIDs.add(importModuleID), - ); + extractImports(demos[demoName].raw).forEach((importModuleID) => { + // detect relative import + detectRelativeImports(demoName, moduleFilepath, 'JS', importModuleID); + importedModuleIDs.add(importModuleID); + }); } if (multipleDemoVersionsUsed) { @@ -343,10 +404,69 @@ module.exports = async function demoLoader() { // But this leads to building both demo version i.e. more build time. demos[demoName].moduleTS = this.mode === 'production' ? moduleID : moduleTS; demos[demoName].rawTS = rawTS; + + // Extract relative imports from the TypeScript version + // of demos which have relative imports in the JS version + if (relativeModules.has(demoName)) { + extractImports(demos[demoName].rawTS).forEach((importModuleID) => { + detectRelativeImports(demoName, moduleTSFilepath, 'TS', importModuleID); + importedModuleIDs.add(importModuleID); + }); + } + demoModuleIDs.add(demos[demoName].moduleTS); } catch (error) { // TS version of the demo doesn't exist. This is fine. } + + /* Map over relative import module IDs and resolve them + * while grouping by demo variant + * From: + * relativeModules: { 'ComboBox.js' => + * { './top100Films.js' => ['JS', 'TS'] } + * } + * To: + * demos["ComboBox.js"].relativeModules = { + * JS: [{ module: './top100Films.js', raw: '...' }], + * TS: [{ module: './top100Films.js', raw: '...' }] + * } + * } + */ + + if (relativeModules.has(demoName)) { + if (!demos[demoName].relativeModules) { + demos[demoName].relativeModules = {}; + } + + await Promise.all( + Array.from(relativeModules.get(demoName)).map(async ([relativeModuleID, variants]) => { + let raw = ''; + try { + raw = await fs.readFile(path.join(path.dirname(moduleFilepath), relativeModuleID), { + encoding: 'utf8', + }); + } catch { + throw new Error( + `Could not find a module for the relative import "${relativeModuleID}" in the demo "${demoName}"`, + ); + } + + const moduleData = { module: relativeModuleID, raw }; + const modules = demos[demoName].relativeModules; + + variants.forEach((variant) => { + if (modules[variant]) { + // Avoid duplicates + if (!modules[variant].some((elem) => elem.module === relativeModuleID)) { + modules[variant].push(moduleData); + } + } else { + modules[variant] = [moduleData]; + } + }); + }), + ); + } }), ); diff --git a/packages/markdown/package.json b/packages/markdown/package.json index 9d6cef39b4b224..a26692062dc126 100644 --- a/packages/markdown/package.json +++ b/packages/markdown/package.json @@ -1,6 +1,6 @@ { "name": "@mui/internal-markdown", - "version": "1.0.2", + "version": "1.0.3", "author": "MUI Team", "description": "MUI markdown parser. This is an internal package not meant for general use.", "main": "./index.js", diff --git a/packages/markdown/prepareMarkdown.js b/packages/markdown/prepareMarkdown.js index caaa61d0fbbd97..878bdea7e768db 100644 --- a/packages/markdown/prepareMarkdown.js +++ b/packages/markdown/prepareMarkdown.js @@ -110,7 +110,7 @@ This unstyled version of the component is the ideal choice for heavy customizati `); } - if (headers.components.length > 0) { + if (headers.components.length > 0 && headers.productId !== 'base-ui') { contents.push(` ## API diff --git a/packages/mui-babel-macros/MuiError.macro.d.ts b/packages/mui-babel-macros/MuiError.macro.d.ts index 53d894b2241058..54293408e59b1a 100644 --- a/packages/mui-babel-macros/MuiError.macro.d.ts +++ b/packages/mui-babel-macros/MuiError.macro.d.ts @@ -1,3 +1,3 @@ export default class MuiError { - constructor(message: string); + constructor(message: string, ...args: string[]); } diff --git a/packages/mui-babel-macros/package.json b/packages/mui-babel-macros/package.json index 2cc41924b72c25..56390a6c12784c 100644 --- a/packages/mui-babel-macros/package.json +++ b/packages/mui-babel-macros/package.json @@ -1,6 +1,6 @@ { "name": "@mui/internal-babel-macros", - "version": "1.0.2", + "version": "1.0.3", "author": "MUI Team", "description": "MUI Babel macros. This is an internal package not meant for general use.", "main": "./MuiError.macro.js", diff --git a/packages/mui-base/package.json b/packages/mui-base/package.json index 08c4b94bcca7f6..a103c186421a98 100644 --- a/packages/mui-base/package.json +++ b/packages/mui-base/package.json @@ -27,8 +27,7 @@ "url": "https://opencollective.com/mui-org" }, "scripts": { - "build": "pnpm build:legacy && pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:types && pnpm build:copy-files", - "build:legacy": "node ../../scripts/build.mjs legacy", + "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:types && pnpm build:copy-files", "build:modern": "node ../../scripts/build.mjs modern", "build:node": "node ../../scripts/build.mjs node", "build:stable": "node ../../scripts/build.mjs stable", diff --git a/packages/mui-base/src/useAutocomplete/useAutocomplete.js b/packages/mui-base/src/useAutocomplete/useAutocomplete.js index 344b2cce0efe0f..45caa7dd2123dc 100644 --- a/packages/mui-base/src/useAutocomplete/useAutocomplete.js +++ b/packages/mui-base/src/useAutocomplete/useAutocomplete.js @@ -10,11 +10,8 @@ import { } from '@mui/utils'; // https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript -// Give up on IE11 support for this feature function stripDiacritics(string) { - return typeof string.normalize !== 'undefined' - ? string.normalize('NFD').replace(/[\u0300-\u036f]/g, '') - : string; + return string.normalize('NFD').replace(/[\u0300-\u036f]/g, ''); } export function createFilterOptions(config = {}) { @@ -56,17 +53,6 @@ export function createFilterOptions(config = {}) { }; } -// To replace with .findIndex() once we stop IE11 support. -function findIndex(array, comp) { - for (let i = 0; i < array.length; i += 1) { - if (comp(array[i])) { - return i; - } - } - - return -1; -} - const defaultFilterOptions = createFilterOptions(); // Number of options to jump in list box when `Page Up` and `Page Down` keys are used. @@ -498,7 +484,7 @@ export function useAutocomplete(props) { const previousHighlightedOption = previousProps.filteredOptions[highlightedIndexRef.current]; if (previousHighlightedOption) { - return findIndex(filteredOptions, (option) => { + return filteredOptions.findIndex((option) => { return getOptionLabel(option) === getOptionLabel(previousHighlightedOption); }); } @@ -539,12 +525,12 @@ export function useAutocomplete(props) { if ( multiple && currentOption && - findIndex(value, (val) => isOptionEqualToValue(currentOption, val)) !== -1 + value.findIndex((val) => isOptionEqualToValue(currentOption, val)) !== -1 ) { return; } - const itemIndex = findIndex(filteredOptions, (optionItem) => + const itemIndex = filteredOptions.findIndex((optionItem) => isOptionEqualToValue(optionItem, valueItem), ); if (itemIndex === -1) { @@ -685,7 +671,7 @@ export function useAutocomplete(props) { } } - const itemIndex = findIndex(newValue, (valueItem) => isOptionEqualToValue(option, valueItem)); + const itemIndex = newValue.findIndex((valueItem) => isOptionEqualToValue(option, valueItem)); if (itemIndex === -1) { newValue.push(option); diff --git a/packages/mui-base/src/useSnackbar/useSnackbar.ts b/packages/mui-base/src/useSnackbar/useSnackbar.ts index d2d73cf641af1f..4b9de6ad0754bb 100644 --- a/packages/mui-base/src/useSnackbar/useSnackbar.ts +++ b/packages/mui-base/src/useSnackbar/useSnackbar.ts @@ -44,8 +44,7 @@ export function useSnackbar(parameters: UseSnackbarParameters = {}): UseSnackbar */ function handleKeyDown(nativeEvent: KeyboardEvent) { if (!nativeEvent.defaultPrevented) { - // IE11, Edge (prior to using Blink?) use 'Esc' - if (nativeEvent.key === 'Escape' || nativeEvent.key === 'Esc') { + if (nativeEvent.key === 'Escape') { // not calling `preventDefault` since we don't know if people may ignore this event e.g. a permanently open snackbar onClose?.(nativeEvent, 'escapeKeyDown'); } diff --git a/packages/mui-codemod/README.md b/packages/mui-codemod/README.md index ac15226a678a07..adcbb49a7f85bc 100644 --- a/packages/mui-codemod/README.md +++ b/packages/mui-codemod/README.md @@ -1054,6 +1054,76 @@ npx @mui/codemod@next deprecations/step-connector-classes ### v6.0.0 +#### `styled-v6` + +Updates the usage of `styled` from `@mui/system@v5` to be compatible with `@pigment-css/react`. + +This codemod transforms the styles based on props to `variants` by looking for `styled` calls: + +```diff + styled('div')(({ theme, disabled }) => ({ + color: theme.palette.primary.main, +- ...(disabled && { +- opacity: 0.5, +- }), ++ variants: [ ++ { ++ prop: 'disabled', ++ style: { ++ opacity: 0.5, ++ }, ++ }, ++ ], + })); +``` + +This codemod can handle complex styles with spread operators, ternary operators, and nested objects. + +However, it has some **limitations**: + +- It does not transform dynamic values as shown below: + + ```js + const ResizableContainer = styled('div')(({ ownerState, theme }) => ({ + width: ownerState.width ?? '100%', + height: ownerState.height ?? '100%', + })); + ``` + + You need to manually declare a CSS variable and set the values using inline styles: + + ```js + // ✅ Recommended way + const ResizableContainer = styled('div')({ + width: 'var(--ResizableContainer-width, 100%)', + height: 'var(--ResizableContainer-height, 100%)', + }); + ``` + +- It does not transform dynamic reference from the theme, for example color palette. + + ```js + const Test = styled('div')(({ ownerState, theme }) => ({ + backgroundColor: (theme.vars || theme).palette[ownerState.color]?.main, + })); + ``` + + You need to manually iterate the theme object and create `variants` for each color. + + ```js + // ✅ Recommended way + const Test = styled('div')(({ theme }) => ({ + variants: Object.entries(theme.palette) + .filter(([color, value]) => value.main) + .map(([color, value]) => ({ + props: { color }, + style: { + backgroundColor: value.main, + }, + })), + })); + ``` + ### v5.0.0 #### `base-use-named-exports` diff --git a/packages/mui-codemod/package.json b/packages/mui-codemod/package.json index da49eb953ddce7..daee2b438602b3 100644 --- a/packages/mui-codemod/package.json +++ b/packages/mui-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@mui/codemod", - "version": "6.0.0-alpha.1", + "version": "6.0.0-alpha.3", "bin": "./codemod.js", "private": false, "author": "MUI Team", diff --git a/packages/mui-codemod/src/v6.0.0/styled/index.js b/packages/mui-codemod/src/v6.0.0/styled/index.js new file mode 100644 index 00000000000000..b848cbfe4e9d99 --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/index.js @@ -0,0 +1 @@ +export { default } from './styled-v6'; diff --git a/packages/mui-codemod/src/v6.0.0/styled/styled-v6.js b/packages/mui-codemod/src/v6.0.0/styled/styled-v6.js new file mode 100644 index 00000000000000..4bef0e598b7eed --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/styled-v6.js @@ -0,0 +1,589 @@ +const MAX_DEPTH = 20; + +/** + * @param {import('jscodeshift').FileInfo} file + * @param {import('jscodeshift').API} api + */ +export default function styledV6(file, api, options) { + const j = api.jscodeshift; + const root = j(file.source); + const printOptions = options.printOptions; + + /** + * + * @param {import('ast-types').namedTypes.MemberExpression | import('ast-types').namedTypes.Identifier} node + */ + function getIdentifierKey(node) { + if (node.type === 'MemberExpression') { + return node.property; + } + return node; + } + + /** + * + * @param {import('ast-types').namedTypes.UnaryExpression | import('ast-types').namedTypes.MemberExpression | import('ast-types').namedTypes.Identifier} node + */ + function getObjectKey(node) { + let tempNode = { ...node }; + while (tempNode.type === 'UnaryExpression') { + tempNode = tempNode.argument; + } + while (tempNode.type === 'MemberExpression') { + tempNode = tempNode.object; + } + return tempNode; + } + + /** + * + * @param {import('ast-types').namedTypes.ObjectExpression} objectExpression + * @param {import('ast-types').namedTypes.BinaryExpression} addtional + */ + function objectToArrowFunction(objectExpression, addtional) { + const paramKeys = new Set(); + let left; + objectExpression.properties.forEach((prop, index) => { + paramKeys.add(prop.key.name); + const result = j.binaryExpression('===', prop.key, prop.value); + if (index === 0) { + left = result; + } else { + left = j.logicalExpression('&&', left, result); + } + }); + if (addtional) { + paramKeys.add(getObjectKey(addtional.left).name); + } + return buildArrowFunctionAST( + paramKeys, + addtional ? j.logicalExpression('&&', left, addtional) : left, + ); + } + + /** + * + * @param {import('ast-types').namedTypes.Identifier | import('ast-types').namedTypes.BinaryExpression | import('ast-types').namedTypes.UnaryExpression} node + */ + function inverseBinaryExpression(node) { + if (node.type === 'Identifier') { + return j.unaryExpression('!', node); + } + if (node.operator === '===') { + return { ...node, operator: '!==' }; + } + if (node.operator === '!==') { + return { ...node, operator: '===' }; + } + if (node.operator === '!') { + if (node.argument?.operator === '!') { + return node.argument; + } + return j.unaryExpression('!', node); + } + return node; + } + + /** + * + * @param {import('ast-types').namedTypes.ObjectExpression} node + */ + function removeProperty(parentNode, child) { + if (parentNode) { + if (parentNode.type === 'ObjectExpression') { + parentNode.properties = parentNode.properties.filter( + (prop) => prop !== child && prop.value !== child, + ); + } + } + } + + function buildObjectAST(jsObject) { + const result = j.objectExpression([]); + Object.entries(jsObject).forEach(([key, value]) => { + result.properties.push(j.objectProperty(j.identifier(key), value)); + }); + return result; + } + + function buildArrowFunctionAST(params, body) { + return j.arrowFunctionExpression( + [ + j.objectPattern( + [...params].map((k) => ({ + ...j.objectProperty(j.identifier(k), j.identifier(k)), + shorthand: true, + })), + ), + ], + body, + ); + } + + /** + * + * @param {{ properties: any[] }} node + * @param {Record} modeStyles + */ + function appendPaletteModeStyles(node, modeStyles) { + Object.entries(modeStyles).forEach(([mode, objectStyles]) => { + node.properties.push( + j.spreadElement( + j.callExpression(j.memberExpression(j.identifier('theme'), j.identifier('applyStyles')), [ + j.stringLiteral(mode), + j.objectExpression(objectStyles), + ]), + ), + ); + }); + } + + /** + * + * @param {import('ast-types').namedTypes.LogicalExpression | import('ast-types').namedTypes.BinaryExpression | import('ast-types').namedTypes.UnaryExpression | import('ast-types').namedTypes.MemberExpression} node + */ + function buildProps(node) { + const properties = []; + const variables = new Set(); + let isAllEqual = true; + let tempNode = { ...node }; + function assignProperties(_node) { + if (_node.type === 'BinaryExpression') { + variables.add(getObjectKey(_node.left).name); + if (_node.operator === '===') { + properties.push(j.objectProperty(getIdentifierKey(_node.left), _node.right)); + } else { + isAllEqual = false; + } + } + if (_node.type === 'MemberExpression' || _node.type === 'Identifier') { + isAllEqual = false; + variables.add(getObjectKey(_node).name); + } + if (_node.type === 'UnaryExpression') { + isAllEqual = false; + if (_node.argument.type === 'UnaryExpression') { + // handle `!!variable` + variables.add(getObjectKey(_node.argument.argument).name); + } else { + // handle `!variable` + variables.add(getObjectKey(_node.argument).name); + } + } + } + let counter = 0; + if (tempNode.type !== 'LogicalExpression') { + assignProperties(tempNode); + } else { + while (tempNode.type === 'LogicalExpression' && counter < MAX_DEPTH) { + counter += 1; + if (tempNode.operator !== '&&') { + isAllEqual = false; + } + + assignProperties(tempNode.right); + if (tempNode.left.type !== 'LogicalExpression') { + assignProperties(tempNode.left); + break; + } + + tempNode = { ...tempNode.left }; + } + } + + if (!isAllEqual) { + return buildArrowFunctionAST(variables, node); + } + return j.objectExpression(properties); + } + + function mergeProps(parentProps, currentProps) { + if (parentProps.type === 'ObjectExpression' && currentProps.type === 'ObjectExpression') { + return j.objectExpression([...parentProps.properties, ...currentProps.properties]); + } + const parentArrow = + parentProps.type === 'ObjectExpression' ? objectToArrowFunction(parentProps) : parentProps; + const currentArrow = + currentProps.type === 'ObjectExpression' ? objectToArrowFunction(currentProps) : currentProps; + const variables = new Set(); + [...parentArrow.params[0].properties, ...currentArrow.params[0].properties].forEach((param) => { + variables.add(param.key.name); + }); + return buildArrowFunctionAST( + variables, + j.logicalExpression('&&', parentArrow.body, currentArrow.body), + ); + } + + function isThemePaletteMode(node) { + return ( + node.type === 'MemberExpression' && + node.object.type === 'MemberExpression' && + node.object.object.name === 'theme' && + node.object.property.name === 'palette' && + node.property.name === 'mode' + ); + } + + let shouldTransform = false; + + root.find(j.CallExpression).forEach((path) => { + const styles = []; + let args = []; + + // styled('div')(...arguments) + if ( + path.node.callee.type === 'Identifier' && + path.node.callee.name === 'styled' && + path.parentPath.node.type === 'CallExpression' + ) { + args = path.parentPath.node.arguments; + } + + // styled.div(...arguments) + if ( + path.node.callee.type === 'MemberExpression' && + path.node.callee.object.type === 'Identifier' && + path.node.callee.object.name === 'styled' + ) { + args = path.node.arguments; + } + + // 1. collecting styles that should be tranformed + args.forEach((arg) => { + if ( + arg.type === 'ArrowFunctionExpression' && + arg.params[0] && + arg.params[0].type === 'ObjectPattern' + ) { + styles.push(arg); + } + }); + + if (!shouldTransform && styles.length > 0) { + shouldTransform = true; + } + + // 2. Find logical spread expressions to convert to variants + styles.forEach((style) => { + const parameters = new Set(); + style.params.forEach((param) => { + if (param.type === 'ObjectPattern') { + param.properties.forEach((prop) => { + parameters.add(prop.key.name); + }); + } + }); + const variants = []; + + if (style.body.type === 'LogicalExpression') { + if ( + style.params[0] && + style.params[0].type === 'ObjectPattern' && + style.params[0].properties.some((prop) => prop.key.name !== 'theme') + ) { + // case: ({ theme, ownerState }) => ownerState.variant === 'regular' && theme.mixins.toolbar + style.body = j.objectExpression([ + j.objectProperty( + j.identifier('variants'), + j.arrayExpression([ + j.objectExpression([ + j.objectProperty(j.identifier('props'), buildProps(style.body.left)), + j.objectProperty(j.identifier('style'), style.body.right), + ]), + ]), + ), + ]); + } + } else if (style.body.type === 'ConditionalExpression') { + // skip ConditionalExpression + } else { + let objectExpression = style.body; + let counter = 0; + while (objectExpression.type !== 'ObjectExpression' && counter < MAX_DEPTH) { + counter += 1; + if (objectExpression.type === 'BlockStatement') { + objectExpression = objectExpression.body.find( + (item) => item.type === 'ReturnStatement', + ).argument; + } + } + + recurseObjectExpression({ node: objectExpression }); + + if (variants.length) { + objectExpression.properties.push( + j.objectProperty( + j.identifier('variants'), + j.arrayExpression( + variants.filter((variant) => { + const props = variant.properties.find((prop) => prop.key.name === 'props'); + const styleVal = variant.properties.find((prop) => prop.key.name === 'style'); + return ( + props && + styleVal && + styleVal.value.properties.length > 0 && + (props.value.type === 'ArrowFunctionExpression' || + props.value.properties.length > 0) + ); + }), + ), + ), + ); + } + } + + function recurseObjectExpression(data) { + if (data.node.type === 'ObjectExpression') { + const modeStyles = {}; // to collect styles from `theme.palette.mode === '...'` + data.node.properties.forEach((prop) => { + if (prop.type === 'ObjectProperty') { + recurseObjectExpression({ + ...data, + node: prop.value, + parentNode: data.node, + key: prop.key, + replaceValue: (newValue) => { + prop.value = newValue; + }, + modeStyles, + }); + } else { + recurseObjectExpression({ ...data, node: prop, parentNode: data.node }); + } + }); + appendPaletteModeStyles(data.node, modeStyles); + } + if (data.node.type === 'SpreadElement') { + if (data.node.argument.type === 'LogicalExpression') { + const paramName = getObjectKey(data.node.argument.left)?.name; + if (paramName && !parameters.has(paramName)) { + return; + } + + const scopeProps = buildProps(data.node.argument.left); + const variant = { + props: data.props ? mergeProps(data.props, scopeProps) : scopeProps, + style: data.node.argument.right, + }; + + const modeStyles = {}; // to collect styles from `theme.palette.mode === '...'` + variant.style.properties.forEach((prop) => { + if (prop.type === 'ObjectProperty') { + recurseObjectExpression({ + ...data, + node: prop.value, + parentNode: variant.style, + props: variant.props, + key: prop.key, + replaceValue: (newValue) => { + prop.value = newValue; + }, + modeStyles, + }); + } else { + recurseObjectExpression({ + ...data, + node: prop, + parentNode: variant.style, + props: variant.props, + }); + } + }); + appendPaletteModeStyles(variant.style, modeStyles); + variants.push(buildObjectAST(variant)); + removeProperty(data.parentNode, data.node); + } + if (data.node.argument.type === 'ConditionalExpression') { + recurseObjectExpression({ ...data, node: data.node.argument, parentNode: data.node }); + removeProperty(data.parentNode, data.node); + } + } + if (data.node.type === 'ConditionalExpression') { + if ( + data.node.test.type === 'BinaryExpression' || + data.node.test.type === 'UnaryExpression' || + data.node.test.type === 'Identifier' + ) { + let leftName = getObjectKey(data.node.test)?.name; + if (data.node.test.left) { + leftName = getObjectKey(data.node.test.left)?.name; + } + if (data.node.test.argument) { + leftName = getObjectKey(data.node.test.argument)?.name; + } + if (parameters.has(leftName) && leftName !== 'theme') { + let props = buildProps(data.node.test); + if (data.props) { + props = mergeProps(data.props, props); + } + const styleVal = data.node.consequent; + let newStyle = styleVal; + if ( + data.key && + (data.key.type === 'Identifier' || data.key.type === 'StringLiteral') + ) { + newStyle = j.objectExpression([j.objectProperty(data.key, styleVal)]); + } + const variant = { + props, + style: newStyle, + }; + variants.push(buildObjectAST(variant)); + + // create another variant with inverted condition + let props2 = buildProps(inverseBinaryExpression(data.node.test)); + if (data.props) { + props2 = mergeProps(data.props, props2); + } + const styleVal2 = data.node.alternate; + let newStyle2 = styleVal2; + if ( + data.key && + (data.key.type === 'Identifier' || data.key.type === 'StringLiteral') + ) { + newStyle2 = j.objectExpression([j.objectProperty(data.key, styleVal2)]); + } + const variant2 = { + props: props2, + style: newStyle2, + }; + variants.push(buildObjectAST(variant2)); + if (data.parentNode?.type === 'ObjectExpression') { + removeProperty(data.parentNode, data.node); + } + } + if ( + leftName === 'theme' && + data.parentNode?.type === 'ObjectExpression' && + data.node.test?.type === 'BinaryExpression' && + isThemePaletteMode(data.node.test.left) + ) { + if ( + data.node.consequent.type !== 'ObjectExpression' && + data.node.alternate.type !== 'ObjectExpression' + ) { + if (data.modeStyles) { + if (!data.modeStyles[data.node.test.right.value]) { + data.modeStyles[data.node.test.right.value] = []; + } + data.modeStyles[data.node.test.right.value].push( + j.objectProperty(data.key, data.node.consequent), + ); + } + data.replaceValue?.(data.node.alternate); + } + } + } + } + if (data.node.type === 'TemplateLiteral') { + if (data.parentNode?.type === 'ObjectExpression') { + const modeStyles = {}; + data.node.expressions.forEach((expression, index) => { + recurseObjectExpression({ + ...data, + node: expression, + parentNode: data.parentNode, + key: data.key, + replaceValue: (newValue) => { + data.node.expressions[index] = newValue; + }, + modeStyles, + }); + }); + if (data.modeStyles) { + Object.entries(modeStyles).forEach(([mode, objectStyles]) => { + const clonedNode = { + ...data.node, + expressions: data.node.expressions.map((expression) => ({ ...expression })), + }; + clonedNode.expressions = objectStyles.map((item) => item.value); + + if (!data.modeStyles[mode]) { + data.modeStyles[mode] = []; + } + data.modeStyles[mode].push(j.objectProperty(data.key, clonedNode)); + }); + } + } + } + if ( + data.key && + data.key.type === 'Identifier' && + data.node.type === 'MemberExpression' && + data.node.object.type === 'ObjectExpression' && + parameters.has(getObjectKey(data.node.property).name) + ) { + data.node.object.properties.forEach((prop) => { + variants.push( + buildObjectAST({ + props: j.objectExpression([ + j.objectProperty( + getIdentifierKey(data.node.property), + j.stringLiteral(prop.key.name), + ), + ]), + style: j.objectExpression([j.objectProperty(data.key, prop.value)]), + }), + ); + }); + removeProperty(data.parentNode, data.node); + } + } + + style.params.forEach((param) => { + if (param.type === 'ObjectPattern') { + param.properties = param.properties.filter((prop) => prop.key.name === 'theme'); + } + }); + }); + + // Replace arrow function with object expression if the arg properties is empty + args.forEach((arg, index) => { + if ( + arg.type === 'ArrowFunctionExpression' && + arg.params[0] && + arg.params[0].type === 'ObjectPattern' && + arg.params[0].properties.length === 0 + ) { + if (arg.body.type === 'ObjectExpression') { + args[index] = arg.body; + } + if (arg.body.type === 'BlockStatement') { + const returnStatement = arg.body.body.find((item) => item.type === 'ReturnStatement'); + if (returnStatement) { + args[index] = returnStatement.argument; + } + } + } + }); + }); + + const transformed = root.toSource(printOptions); + + if (shouldTransform) { + // recast adds extra newlines that we don't want, https://github.com/facebook/jscodeshift/issues/249 + // need to remove them manually + const lines = []; + let isInStyled = false; + transformed.split('\n').forEach((line, index, array) => { + if (!isInStyled) { + lines.push(line); + } else if ( + line !== '' || + (line === '' && array[index + 1] && array[index + 1].includes('return')) + ) { + if (line.match(/^}\)+(\({}\)|\(\))?;?$/) || line.match(/^\);?$/)) { + isInStyled = false; + } + lines.push(line); + } + if (line.includes('styled.') || line.includes('styled(')) { + isInStyled = true; + } + }); + return lines.join('\n'); + } + + return transformed; +} diff --git a/packages/mui-codemod/src/v6.0.0/styled/styled-v6.test.js b/packages/mui-codemod/src/v6.0.0/styled/styled-v6.test.js new file mode 100644 index 00000000000000..7dee2d833d463f --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/styled-v6.test.js @@ -0,0 +1,181 @@ +import path from 'path'; +import { expect } from 'chai'; +import { jscodeshift } from '../../../testUtils'; +import transform from './styled-v6'; +import readFile from '../../util/readFile'; + +function read(fileName) { + return readFile(path.join(__dirname, fileName)); +} + +describe('@mui/codemod', () => { + describe('v6.0.0', () => { + describe('basic styled-v6', () => { + it('transforms props as needed', () => { + const actual = transform( + { source: read('./test-cases/BasicStyled.actual.js') }, + { jscodeshift }, + {}, + ); + + const expected = read('./test-cases/BasicStyled.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + + it('should be idempotent', () => { + const actual = transform( + { source: read('./test-cases/BasicStyled.expected.js') }, + { jscodeshift }, + {}, + ); + + const expected = read('./test-cases/BasicStyled.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + }); + + describe('logical styled-v6', () => { + it('transforms props as needed', () => { + const actual = transform( + { source: read('./test-cases/LogicalStyled.actual.js') }, + { jscodeshift }, + { printOptions: { trailingComma: false } }, + ); + + const expected = read('./test-cases/LogicalStyled.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + + it('should be idempotent', () => { + const actual = transform( + { source: read('./test-cases/LogicalStyled.expected.js') }, + { jscodeshift }, + {}, + ); + + const expected = read('./test-cases/LogicalStyled.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + }); + + describe('nested spread styled-v6', () => { + it('transforms props as needed', () => { + const actual = transform( + { source: read('./test-cases/NestedSpread.actual.js') }, + { jscodeshift }, + { printOptions: { trailingComma: false } }, + ); + + const expected = read('./test-cases/NestedSpread.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + + it('should be idempotent', () => { + const actual = transform( + { source: read('./test-cases/NestedSpread.expected.js') }, + { jscodeshift }, + {}, + ); + + const expected = read('./test-cases/NestedSpread.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + }); + + describe('object map styled-v6', () => { + it('transforms props as needed', () => { + const actual = transform( + { source: read('./test-cases/ObjectMap.actual.js') }, + { jscodeshift }, + { printOptions: { trailingComma: false } }, + ); + + const expected = read('./test-cases/ObjectMap.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + + it('should be idempotent', () => { + const actual = transform( + { source: read('./test-cases/ObjectMap.expected.js') }, + { jscodeshift }, + {}, + ); + + const expected = read('./test-cases/ObjectMap.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + }); + + describe('conditional styled-v6', () => { + it('transforms props as needed', () => { + const actual = transform( + { source: read('./test-cases/ConditionalStyled.actual.js') }, + { jscodeshift }, + { printOptions: { trailingComma: false } }, + ); + + const expected = read('./test-cases/ConditionalStyled.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + + it('should be idempotent', () => { + const actual = transform( + { source: read('./test-cases/ConditionalStyled.expected.js') }, + { jscodeshift }, + {}, + ); + + const expected = read('./test-cases/ConditionalStyled.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + }); + + describe('theme palette mode styled-v6', () => { + it('transforms props as needed', () => { + const actual = transform( + { source: read('./test-cases/ThemePaletteMode.actual.js') }, + { jscodeshift }, + { printOptions: { trailingComma: false } }, + ); + + const expected = read('./test-cases/ThemePaletteMode.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + + it('should be idempotent', () => { + const actual = transform( + { source: read('./test-cases/ThemePaletteMode.expected.js') }, + { jscodeshift }, + {}, + ); + + const expected = read('./test-cases/ThemePaletteMode.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + }); + + describe('theme palette mode and variants styled-v6', () => { + it('transforms props as needed', () => { + const actual = transform( + { source: read('./test-cases/VariantAndModeStyled.actual.js') }, + { jscodeshift }, + { printOptions: { trailingComma: false } }, + ); + + const expected = read('./test-cases/VariantAndModeStyled.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + + it('should be idempotent', () => { + const actual = transform( + { source: read('./test-cases/VariantAndModeStyled.expected.js') }, + { jscodeshift }, + {}, + ); + + const expected = read('./test-cases/VariantAndModeStyled.expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + }); + }); +}); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/BasicStyled.actual.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/BasicStyled.actual.js new file mode 100644 index 00000000000000..831808277ff08d --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/BasicStyled.actual.js @@ -0,0 +1,60 @@ +const FormHelperTextRoot = styled('p')(({ theme, ownerState, disabled }) => ({ + color: (theme.vars || theme).palette.text.secondary, + ...theme.typography.caption, + textAlign: 'left', + [`&.${formHelperTextClasses.disabled}`]: { + color: (theme.vars || theme).palette.text.disabled, + }, + ...(ownerState.size === 'small' && { + marginTop: 4, + }), + ...(ownerState.size === 'small' && + ownerState.variant === 'contained' && { + marginTop: 6, + }), + ...(ownerState.size === 'small' && + ownerState.variant === 'contained' && + disabled && { + marginTop: 6, + }), + ...(ownerState.size !== 'small' && { + marginBottom: 4, + }), + ...(ownerState.size !== 'small' && + ownerState.variant !== 'contained' && + !disabled && { + marginBottom: 6, + }), + ...(ownerState.contained && { + marginLeft: 14, + marginRight: 14, + }), + ...(!ownerState.contained && { + marginTop: 14, + marginBottom: 14, + }), + ...(!!ownerState.disabled && { + opacity: 0.5, + }), +})); + +const Component = styled.div(({ theme, ownerState }) => ({ + ...theme.typography.caption, + ...(ownerState.size === 'small' && { + marginTop: (theme.vars || theme).spacing(1), + }), +})); + +const ImageListRoot = styled('ul')(({ ownerState }) => { + return { + display: 'grid', + overflowY: 'auto', + listStyle: 'none', + padding: 0, + // Add iOS momentum scrolling for iOS < 13.0 + WebkitOverflowScrolling: 'touch', + ...(ownerState.variant === 'masonry' && { + display: 'block', + }), + }; +}); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/BasicStyled.expected.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/BasicStyled.expected.js new file mode 100644 index 00000000000000..d7aa53897b899b --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/BasicStyled.expected.js @@ -0,0 +1,119 @@ +const FormHelperTextRoot = styled('p')(({ + theme +}) => ({ + color: (theme.vars || theme).palette.text.secondary, + ...theme.typography.caption, + textAlign: 'left', + [`&.${formHelperTextClasses.disabled}`]: { + color: (theme.vars || theme).palette.text.disabled, + }, + variants: [{ + props: { + size: 'small' + }, + style: { + marginTop: 4, + } + }, { + props: { + variant: 'contained', + size: 'small' + }, + style: { + marginTop: 6, + } + }, { + props: ( + { + disabled, + ownerState + } + ) => ownerState.size === 'small' && + ownerState.variant === 'contained' && + disabled, + style: { + marginTop: 6, + } + }, { + props: ( + { + ownerState + } + ) => ownerState.size !== 'small', + style: { + marginBottom: 4, + } + }, { + props: ( + { + disabled, + ownerState + } + ) => ownerState.size !== 'small' && + ownerState.variant !== 'contained' && + !disabled, + style: { + marginBottom: 6, + } + }, { + props: ( + { + ownerState + } + ) => ownerState.contained, + style: { + marginLeft: 14, + marginRight: 14, + } + }, { + props: ( + { + ownerState + } + ) => !ownerState.contained, + style: { + marginTop: 14, + marginBottom: 14, + } + }, { + props: ( + { + ownerState + } + ) => !!ownerState.disabled, + style: { + opacity: 0.5, + } + }] +})); + +const Component = styled.div(({ + theme +}) => ({ + ...theme.typography.caption, + variants: [{ + props: { + size: 'small' + }, + style: { + marginTop: (theme.vars || theme).spacing(1), + } + }] +})); + +const ImageListRoot = styled('ul')({ + display: 'grid', + overflowY: 'auto', + listStyle: 'none', + padding: 0, + // Add iOS momentum scrolling for iOS < 13.0 + WebkitOverflowScrolling: 'touch', + variants: [{ + props: { + variant: 'masonry' + }, + style: { + display: 'block', + } + }] +}); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/ConditionalStyled.actual.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/ConditionalStyled.actual.js new file mode 100644 index 00000000000000..c697bd74b69d85 --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/ConditionalStyled.actual.js @@ -0,0 +1,125 @@ +const LinearProgressBar1 = styled('span', { + name: 'MuiLinearProgress', + slot: 'Bar1', + overridesResolver: (props, styles) => { + const { ownerState } = props; + + return [ + styles.bar, + styles[`barColor${capitalize(ownerState.color)}`], + (ownerState.variant === 'indeterminate' || ownerState.variant === 'query') && + styles.bar1Indeterminate, + ownerState.variant === 'determinate' && styles.bar1Determinate, + ownerState.variant === 'buffer' && styles.bar1Buffer, + ]; + }, +})(({ ownerState, theme }) => ({ + ...(ownerState.variant === 'buffer' && { + backgroundColor: + ownerState.color !== 'normal' + ? 'currentColor' + : (theme.vars || theme).palette[ownerState.color].light, + '&:hover': { + ...(ownerState.color !== 'inherit' + ? { + backgroundColor: (theme.vars || theme).palette[ownerState.color].dark, + } + : { + backgroundColor: 'currentColor', + }), + }, + }), + ...(ownerState.variant !== 'buffer' && { + backgroundColor: + ownerState.color === 'inherit' + ? 'currentColor' + : (theme.vars || theme).palette[ownerState.color].main, + }), +})); + +const ExpandMore = styled((props) => { + const { expand, ...other } = props; + return ; +})(({ theme, expand }) => ({ + transform: !expand ? 'rotate(0deg)' : 'rotate(180deg)', + marginLeft: 'auto', + transition: theme.transitions.create('transform', { + duration: theme.transitions.duration.shortest, + }), +})); + +const Main = styled('main', { + shouldForwardProp: (prop) => prop !== 'disableToc', +})(({ disableToc, theme }) => ({ + minHeight: '100vh', + display: 'grid', + width: '100%', + ...(disableToc + ? { + [theme.breakpoints.up('md')]: { + marginRight: TOC_WIDTH / 2, + }, + } + : { + [theme.breakpoints.up('md')]: { + gridTemplateColumns: `1fr ${TOC_WIDTH}px`, + }, + }), + '& .markdown-body .comment-link': { + display: 'flex', + }, +})); + +const StyledAppContainer = styled(AppContainer, { + shouldForwardProp: (prop) => prop !== 'disableAd' && prop !== 'hasTabs' && prop !== 'disableToc', +})(({ disableAd, hasTabs, disableToc, 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, + ...(disableToc + ? { + // 105ch ≈ 930px + maxWidth: `calc(105ch + ${TOC_WIDTH / 2}px)`, + } + : { + // We're mostly hosting text content so max-width by px does not make sense considering font-size is system-adjustable. + fontFamily: 'Arial', + // 105ch ≈ 930px + maxWidth: '105ch', + }), + ...(!disableAd && { + ...(hasTabs + ? { + '&& .component-tabs .MuiTabs-root': { + // 40px matches MarkdownElement h2 margin-top. + marginBottom: `calc(${theme.spacing(AD_MARGIN_TOP)} + ${AD_HEIGHT_MOBILE}px + 40px)`, + [theme.breakpoints.up('sm')]: { + marginBottom: `calc(${theme.spacing(AD_MARGIN_TOP)} + ${AD_HEIGHT}px + 40px)`, + }, + }, + '&& .component-tabs.ad .MuiTabs-root': { + marginBottom: 0, + }, + } + : { + '&& .description': { + marginBottom: theme.spacing(AD_MARGIN_BOTTOM), + paddingBottom: `calc(${theme.spacing(AD_MARGIN_TOP)} + ${AD_HEIGHT_MOBILE}px)`, + [theme.breakpoints.up('sm')]: { + paddingBottom: `calc(${theme.spacing(AD_MARGIN_TOP)} + ${AD_HEIGHT}px)`, + }, + }, + '&& .description.ad': { + paddingBottom: 0, + marginBottom: 0, + }, + }), + }), + [theme.breakpoints.up('lg')]: { + paddingLeft: '60px', + paddingRight: '60px', + }, + }; +}); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/ConditionalStyled.expected.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/ConditionalStyled.expected.js new file mode 100644 index 00000000000000..cafe6f81cf1ffb --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/ConditionalStyled.expected.js @@ -0,0 +1,232 @@ +const LinearProgressBar1 = styled('span', { + name: 'MuiLinearProgress', + slot: 'Bar1', + overridesResolver: (props, styles) => { + const { ownerState } = props; + + return [ + styles.bar, + styles[`barColor${capitalize(ownerState.color)}`], + (ownerState.variant === 'indeterminate' || ownerState.variant === 'query') && + styles.bar1Indeterminate, + ownerState.variant === 'determinate' && styles.bar1Determinate, + ownerState.variant === 'buffer' && styles.bar1Buffer, + ]; + }, +})(({ + theme +}) => ({ + variants: [{ + props: ( + { + variant, + ownerState + } + ) => variant === 'buffer' && ownerState.color !== 'normal', + style: { + backgroundColor: 'currentColor' + } + }, { + props: { + variant: 'buffer', + color: 'normal' + }, + style: { + backgroundColor: (theme.vars || theme).palette[ownerState.color].light + } + }, { + props: ( + { + variant, + ownerState + } + ) => variant === 'buffer' && ownerState.color !== 'inherit', + style: { + '&:hover': { + backgroundColor: (theme.vars || theme).palette[ownerState.color].dark, + } + } + }, { + props: { + variant: 'buffer', + color: 'inherit' + }, + style: { + '&:hover': { + backgroundColor: 'currentColor', + } + } + }, { + props: { + variant: 'buffer' + }, + style: { + '&:hover': {} + } + }, { + props: ( + { + ownerState, + color + } + ) => ownerState.variant !== 'buffer' && color === 'inherit', + style: { + backgroundColor: 'currentColor' + } + }, { + props: ( + { + ownerState + } + ) => ownerState.variant !== 'buffer' && ownerState.color !== 'inherit', + style: { + backgroundColor: (theme.vars || theme).palette[ownerState.color].main + } + }] +})); + +const ExpandMore = styled((props) => { + const { expand, ...other } = props; + return ; +})(({ + theme +}) => ({ + marginLeft: 'auto', + transition: theme.transitions.create('transform', { + duration: theme.transitions.duration.shortest, + }), + variants: [{ + props: ( + { + expand + } + ) => !expand, + style: { + transform: 'rotate(0deg)' + } + }, { + props: ( + { + expand + } + ) => !!expand, + style: { + transform: 'rotate(180deg)' + } + }], +})); + +const Main = styled('main', { + shouldForwardProp: (prop) => prop !== 'disableToc', +})(({ + theme +}) => ({ + minHeight: '100vh', + display: 'grid', + width: '100%', + '& .markdown-body .comment-link': { + display: 'flex', + }, + variants: [{ + props: ( + { + disableToc + } + ) => disableToc, + style: { + [theme.breakpoints.up('md')]: { + marginRight: TOC_WIDTH / 2, + }, + } + }, { + props: ( + { + disableToc + } + ) => !disableToc, + style: { + [theme.breakpoints.up('md')]: { + gridTemplateColumns: `1fr ${TOC_WIDTH}px`, + }, + } + }] +})); + +const StyledAppContainer = styled(AppContainer, { + shouldForwardProp: (prop) => prop !== 'disableAd' && prop !== 'hasTabs' && prop !== 'disableToc', +})(({ + 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, + [theme.breakpoints.up('lg')]: { + paddingLeft: '60px', + paddingRight: '60px', + }, + variants: [{ + props: ( + { + disableToc + } + ) => disableToc, + style: { + // 105ch ≈ 930px + maxWidth: `calc(105ch + ${TOC_WIDTH / 2}px)`, + } + }, { + props: ( + { + disableToc + } + ) => !disableToc, + style: { + // We're mostly hosting text content so max-width by px does not make sense considering font-size is system-adjustable. + fontFamily: 'Arial', + // 105ch ≈ 930px + maxWidth: '105ch', + } + }, { + props: ( + { + disableAd, + hasTabs + } + ) => !disableAd && hasTabs, + style: { + '&& .component-tabs .MuiTabs-root': { + // 40px matches MarkdownElement h2 margin-top. + marginBottom: `calc(${theme.spacing(AD_MARGIN_TOP)} + ${AD_HEIGHT_MOBILE}px + 40px)`, + [theme.breakpoints.up('sm')]: { + marginBottom: `calc(${theme.spacing(AD_MARGIN_TOP)} + ${AD_HEIGHT}px + 40px)`, + }, + }, + '&& .component-tabs.ad .MuiTabs-root': { + marginBottom: 0, + }, + } + }, { + props: ( + { + disableAd, + hasTabs + } + ) => !disableAd && !hasTabs, + style: { + '&& .description': { + marginBottom: theme.spacing(AD_MARGIN_BOTTOM), + paddingBottom: `calc(${theme.spacing(AD_MARGIN_TOP)} + ${AD_HEIGHT_MOBILE}px)`, + [theme.breakpoints.up('sm')]: { + paddingBottom: `calc(${theme.spacing(AD_MARGIN_TOP)} + ${AD_HEIGHT}px)`, + }, + }, + '&& .description.ad': { + paddingBottom: 0, + marginBottom: 0, + }, + } + }] + }; +}); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/LogicalStyled.actual.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/LogicalStyled.actual.js new file mode 100644 index 00000000000000..1c19e8f6cfcbd6 --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/LogicalStyled.actual.js @@ -0,0 +1,17 @@ +const ToolbarRoot = styled('div', { + name: 'MuiToolbar', + slot: 'Root', + overridesResolver: (props, styles) => { + const { ownerState } = props; + + return [styles.root, !ownerState.disableGutters && styles.gutters, styles[ownerState.variant]]; + }, +})( + ({ theme, ownerState }) => ownerState.variant === 'regular' && theme.mixins.toolbar, + ({ theme, ownerState }) => ownerState.variant !== 'regular' && theme.mixins.toolbar2, + ({ theme, ownerState, disabled }) => + ownerState.variant === 'regular' && disabled && theme.mixins.toolbar3, + ({ theme, ownerState, disabled }) => + ownerState.variant !== 'regular' && !disabled && theme.mixins.toolbar4, + ({ theme }) => theme.vars && theme.mixins.toolbar5, +); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/LogicalStyled.expected.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/LogicalStyled.expected.js new file mode 100644 index 00000000000000..f5f59ecd6d0be0 --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/LogicalStyled.expected.js @@ -0,0 +1,61 @@ +const ToolbarRoot = styled('div', { + name: 'MuiToolbar', + slot: 'Root', + overridesResolver: (props, styles) => { + const { ownerState } = props; + + return [styles.root, !ownerState.disableGutters && styles.gutters, styles[ownerState.variant]]; + }, +})( + ({ + theme + }) => ({ + variants: [{ + props: { + variant: 'regular' + }, + style: theme.mixins.toolbar + }] + }), + ({ + theme + }) => ({ + variants: [{ + props: ( + { + ownerState + } + ) => ownerState.variant !== 'regular', + style: theme.mixins.toolbar2 + }] + }), + ({ + theme + }) => + ({ + variants: [{ + props: ( + { + disabled, + ownerState + } + ) => ownerState.variant === 'regular' && disabled, + style: theme.mixins.toolbar3 + }] + }), + ({ + theme + }) => + ({ + variants: [{ + props: ( + { + disabled, + ownerState + } + ) => ownerState.variant !== 'regular' && !disabled, + style: theme.mixins.toolbar4 + }] + }), + ({ theme }) => theme.vars && theme.mixins.toolbar5, +); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/NestedSpread.actual.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/NestedSpread.actual.js new file mode 100644 index 00000000000000..7b8c87c9cdb595 --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/NestedSpread.actual.js @@ -0,0 +1,46 @@ +const Component = styled('div')(({ theme, ownerState }) => { + const palette = (theme.vars || theme).palette?.[ownerState.color]; + return { + overflow: 'visible', // Explicitly set the default value to solve a bug on IE11. + color: (theme.vars || theme).palette.action.active, + transition: theme.transitions.create('background-color', { + duration: theme.transitions.duration.shortest, + }), + ...(!ownerState.disableRipple && { + '&:hover': { + backgroundColor: theme.vars + ? `rgba(${theme.vars.palette.action.activeChannel} / ${theme.vars.palette.action.hoverOpacity})` + : alpha(theme.palette.action.active, theme.palette.action.hoverOpacity), + // Reset on touch devices, it doesn't add specificity + '@media (hover: none)': { + backgroundColor: 'transparent', + }, + }, + }), + ...(ownerState.edge === 'start' && { + marginLeft: ownerState.size === 'small' ? -3 : -12, + }), + ...(ownerState.edge === 'end' && { + marginRight: ownerState.size === 'small' ? -3 : -12, + }), + ...(ownerState.color !== 'inherit' && + ownerState.color !== 'default' && { + color: palette?.main, + ...(!ownerState.disableRipple && { + '&:hover': { + // The codemod won't handle this case when the variable is not declared in the style argument. + // In this case, the `palette` create a new variable in the style argument. + ...(palette && { + backgroundColor: theme.vars + ? `rgba(${palette.mainChannel} / ${theme.vars.palette.action.hoverOpacity})` + : alpha(palette.main, theme.palette.action.hoverOpacity), + }), + // Reset on touch devices, it doesn't add specificity + '@media (hover: none)': { + backgroundColor: 'transparent', + }, + }, + }), + }), + }; +}); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/NestedSpread.expected.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/NestedSpread.expected.js new file mode 100644 index 00000000000000..f19cf12d71209d --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/NestedSpread.expected.js @@ -0,0 +1,99 @@ +const Component = styled('div')(({ + theme +}) => { + const palette = (theme.vars || theme).palette?.[ownerState.color]; + return { + // Explicitly set the default value to solve a bug on IE11. + overflow: 'visible', + color: (theme.vars || theme).palette.action.active, + transition: theme.transitions.create('background-color', { + duration: theme.transitions.duration.shortest, + }), + variants: [{ + props: ( + { + ownerState + } + ) => !ownerState.disableRipple, + style: { + '&:hover': { + backgroundColor: theme.vars + ? `rgba(${theme.vars.palette.action.activeChannel} / ${theme.vars.palette.action.hoverOpacity})` + : alpha(theme.palette.action.active, theme.palette.action.hoverOpacity), + // Reset on touch devices, it doesn't add specificity + '@media (hover: none)': { + backgroundColor: 'transparent', + }, + }, + } + }, { + props: { + edge: 'start', + size: 'small' + }, + style: { + marginLeft: -3 + } + }, { + props: ( + { + edge, + ownerState + } + ) => edge === 'start' && ownerState.size !== 'small', + style: { + marginLeft: -12 + } + }, { + props: { + edge: 'end', + size: 'small' + }, + style: { + marginRight: -3 + } + }, { + props: ( + { + edge, + ownerState + } + ) => edge === 'end' && ownerState.size !== 'small', + style: { + marginRight: -12 + } + }, { + props: ( + { + ownerState + } + ) => ownerState.color !== 'inherit' && + ownerState.color !== 'default' && !ownerState.disableRipple, + style: { + '&:hover': { + // The codemod won't handle this case when the variable is not declared in the style argument. + // In this case, the `palette` create a new variable in the style argument. + ...(palette && { + backgroundColor: theme.vars + ? `rgba(${palette.mainChannel} / ${theme.vars.palette.action.hoverOpacity})` + : alpha(palette.main, theme.palette.action.hoverOpacity), + }), + // Reset on touch devices, it doesn't add specificity + '@media (hover: none)': { + backgroundColor: 'transparent', + }, + }, + } + }, { + props: ( + { + ownerState + } + ) => ownerState.color !== 'inherit' && + ownerState.color !== 'default', + style: { + color: palette?.main + } + }] + }; +}); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/ObjectMap.actual.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/ObjectMap.actual.js new file mode 100644 index 00000000000000..2460dfd28078e7 --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/ObjectMap.actual.js @@ -0,0 +1,29 @@ +const IconRoot = styled('span')(({ theme, ownerState }) => ({ + userSelect: 'none', + width: '1em', + height: '1em', + // Chrome fix for https://bugs.chromium.org/p/chromium/issues/detail?id=820541 + // To remove at some point. + overflow: 'hidden', + display: 'inline-block', // allow overflow hidden to take action + textAlign: 'center', // support non-square icon + flexShrink: 0, + fontSize: { + inherit: 'inherit', + small: theme.typography.pxToRem(20), + medium: theme.typography.pxToRem(24), + large: theme.typography.pxToRem(36), + }[ownerState.fontSize], + // TODO v5 deprecate, v6 remove for sx + color: { + primary: (theme.vars || theme).palette.primary.main, + secondary: (theme.vars || theme).palette.secondary.main, + info: (theme.vars || theme).palette.info.main, + success: (theme.vars || theme).palette.success.main, + warning: (theme.vars || theme).palette.warning.main, + action: (theme.vars || theme).palette.action.active, + error: (theme.vars || theme).palette.error.main, + disabled: (theme.vars || theme).palette.action.disabled, + inherit: undefined, + }[ownerState.color], +})); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/ObjectMap.expected.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/ObjectMap.expected.js new file mode 100644 index 00000000000000..e4e787da2443ff --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/ObjectMap.expected.js @@ -0,0 +1,107 @@ +const IconRoot = styled('span')(({ + theme +}) => ({ + userSelect: 'none', + width: '1em', + height: '1em', + // Chrome fix for https://bugs.chromium.org/p/chromium/issues/detail?id=820541 + // To remove at some point. + overflow: 'hidden', + // allow overflow hidden to take action + display: 'inline-block', + // support non-square icon + textAlign: 'center', + flexShrink: 0, + variants: [{ + props: { + fontSize: "inherit" + }, + style: { + fontSize: 'inherit' + } + }, { + props: { + fontSize: "small" + }, + style: { + fontSize: theme.typography.pxToRem(20) + } + }, { + props: { + fontSize: "medium" + }, + style: { + fontSize: theme.typography.pxToRem(24) + } + }, { + props: { + fontSize: "large" + }, + style: { + fontSize: theme.typography.pxToRem(36) + } + }, { + props: { + color: "primary" + }, + style: { + color: (theme.vars || theme).palette.primary.main + } + }, { + props: { + color: "secondary" + }, + style: { + color: (theme.vars || theme).palette.secondary.main + } + }, { + props: { + color: "info" + }, + style: { + color: (theme.vars || theme).palette.info.main + } + }, { + props: { + color: "success" + }, + style: { + color: (theme.vars || theme).palette.success.main + } + }, { + props: { + color: "warning" + }, + style: { + color: (theme.vars || theme).palette.warning.main + } + }, { + props: { + color: "action" + }, + style: { + color: (theme.vars || theme).palette.action.active + } + }, { + props: { + color: "error" + }, + style: { + color: (theme.vars || theme).palette.error.main + } + }, { + props: { + color: "disabled" + }, + style: { + color: (theme.vars || theme).palette.action.disabled + } + }, { + props: { + color: "inherit" + }, + style: { + color: undefined + } + }] +})); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/ThemePaletteMode.actual.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/ThemePaletteMode.actual.js new file mode 100644 index 00000000000000..14f35faf74a0ef --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/ThemePaletteMode.actual.js @@ -0,0 +1,58 @@ +const Test = styled('div')(({ theme }) => ({ + color: theme.palette.mode === 'dark' ? theme.palette.primary.light : theme.palette.primary.main, + background: `linear-gradient(45deg, ${theme.palette.mode === 'dark' ? theme.palette.primary[400] : theme.palette.primary[600]} 30%, ${theme.palette.mode === 'dark' ? theme.palette.primary[200] : theme.palette.primary[500]} 90%})`, +})); + +const StyledPopper = styled(Popper)(({ theme }) => ({ + border: `1px solid ${theme.palette.mode === 'light' ? '#e1e4e8' : '#30363d'}`, + boxShadow: `0 8px 24px ${ + theme.palette.mode === 'light' ? 'rgba(149, 157, 165, 0.2)' : 'rgb(1, 4, 9)' + }`, + borderRadius: 6, + width: 300, + zIndex: theme.zIndex.modal, + fontSize: 13, + color: theme.palette.mode === 'light' ? '#24292e' : '#c9d1d9', + backgroundColor: theme.palette.mode === 'light' ? '#fff' : '#1c2128', +})); + +const AntSwitch = styled(Switch)(({ theme }) => ({ + width: 28, + height: 16, + padding: 0, + display: 'flex', + '&:active': { + '& .MuiSwitch-thumb': { + width: 15, + }, + '& .MuiSwitch-switchBase.Mui-checked': { + transform: 'translateX(9px)', + }, + }, + '& .MuiSwitch-switchBase': { + padding: 2, + '&.Mui-checked': { + transform: 'translateX(12px)', + color: '#fff', + '& + .MuiSwitch-track': { + opacity: 1, + backgroundColor: theme.palette.mode === 'dark' ? '#177ddc' : '#1890ff', + }, + }, + }, + '& .MuiSwitch-thumb': { + boxShadow: '0 2px 4px 0 rgb(0 35 11 / 20%)', + width: 12, + height: 12, + borderRadius: 6, + transition: theme.transitions.create(['width'], { + duration: 200, + }), + }, + '& .MuiSwitch-track': { + borderRadius: 16 / 2, + opacity: 1, + backgroundColor: theme.palette.mode === 'dark' ? 'rgba(255,255,255,.35)' : 'rgba(0,0,0,.25)', + boxSizing: 'border-box', + }, +})); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/ThemePaletteMode.expected.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/ThemePaletteMode.expected.js new file mode 100644 index 00000000000000..1e852ec767882c --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/ThemePaletteMode.expected.js @@ -0,0 +1,74 @@ +const Test = styled('div')(({ theme }) => ({ + color: theme.palette.primary.main, + background: `linear-gradient(45deg, ${theme.palette.primary[600]} 30%, ${theme.palette.primary[500]} 90%})`, + ...theme.applyStyles("dark", { + color: theme.palette.primary.light, + background: `linear-gradient(45deg, ${theme.palette.primary[400]} 30%, ${theme.palette.primary[200]} 90%})` + }) +})); + +const StyledPopper = styled(Popper)(({ theme }) => ({ + border: `1px solid ${'#30363d'}`, + boxShadow: `0 8px 24px ${ + 'rgb(1, 4, 9)' + }`, + borderRadius: 6, + width: 300, + zIndex: theme.zIndex.modal, + fontSize: 13, + color: '#c9d1d9', + backgroundColor: '#1c2128', + ...theme.applyStyles("light", { + border: `1px solid ${'#e1e4e8'}`, + boxShadow: `0 8px 24px ${'rgba(149, 157, 165, 0.2)'}`, + color: '#24292e', + backgroundColor: '#fff' + }) +})); + +const AntSwitch = styled(Switch)(({ theme }) => ({ + width: 28, + height: 16, + padding: 0, + display: 'flex', + '&:active': { + '& .MuiSwitch-thumb': { + width: 15, + }, + '& .MuiSwitch-switchBase.Mui-checked': { + transform: 'translateX(9px)', + }, + }, + '& .MuiSwitch-switchBase': { + padding: 2, + '&.Mui-checked': { + transform: 'translateX(12px)', + color: '#fff', + '& + .MuiSwitch-track': { + opacity: 1, + backgroundColor: '#1890ff', + ...theme.applyStyles("dark", { + backgroundColor: '#177ddc' + }) + }, + }, + }, + '& .MuiSwitch-thumb': { + boxShadow: '0 2px 4px 0 rgb(0 35 11 / 20%)', + width: 12, + height: 12, + borderRadius: 6, + transition: theme.transitions.create(['width'], { + duration: 200, + }), + }, + '& .MuiSwitch-track': { + borderRadius: 16 / 2, + opacity: 1, + backgroundColor: 'rgba(0,0,0,.25)', + boxSizing: 'border-box', + ...theme.applyStyles("dark", { + backgroundColor: 'rgba(255,255,255,.35)' + }) + }, +})); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/VariantAndModeStyled.actual.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/VariantAndModeStyled.actual.js new file mode 100644 index 00000000000000..de31de9a2d874e --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/VariantAndModeStyled.actual.js @@ -0,0 +1,7 @@ +const Component = styled.div(({ theme, ownerState }) => ({ + ...theme.typography.caption, + ...(ownerState.size === 'small' && { + marginTop: (theme.vars || theme).spacing(1), + color: theme.palette.mode === 'dark' ? theme.palette.primary.light : theme.palette.primary.main, + }), +})); diff --git a/packages/mui-codemod/src/v6.0.0/styled/test-cases/VariantAndModeStyled.expected.js b/packages/mui-codemod/src/v6.0.0/styled/test-cases/VariantAndModeStyled.expected.js new file mode 100644 index 00000000000000..52780f9917f951 --- /dev/null +++ b/packages/mui-codemod/src/v6.0.0/styled/test-cases/VariantAndModeStyled.expected.js @@ -0,0 +1,17 @@ +const Component = styled.div(({ + theme +}) => ({ + ...theme.typography.caption, + variants: [{ + props: { + size: 'small' + }, + style: { + marginTop: (theme.vars || theme).spacing(1), + color: theme.palette.primary.main, + ...theme.applyStyles("dark", { + color: theme.palette.primary.light + }) + } + }] +})); diff --git a/packages/mui-core-downloads-tracker/package.json b/packages/mui-core-downloads-tracker/package.json index a2aa0d9631db7b..a023a1cf1da6c7 100644 --- a/packages/mui-core-downloads-tracker/package.json +++ b/packages/mui-core-downloads-tracker/package.json @@ -1,6 +1,6 @@ { "name": "@mui/core-downloads-tracker", - "version": "6.0.0-alpha.2", + "version": "6.0.0-alpha.3", "private": false, "author": "MUI Team", "description": "Internal package to track number of downloads of our design system libraries", diff --git a/packages/mui-docs/package.json b/packages/mui-docs/package.json index 54f3b4c83f9a47..93bf574db956ff 100644 --- a/packages/mui-docs/package.json +++ b/packages/mui-docs/package.json @@ -1,6 +1,6 @@ { "name": "@mui/docs", - "version": "6.0.0-alpha.2", + "version": "6.0.0-alpha.3", "private": false, "author": "MUI Team", "description": "MUI Docs - Documentation building blocks.", @@ -23,8 +23,7 @@ }, "homepage": "https://github.com/mui/material-ui/tree/master/packages/mui-docs", "scripts": { - "build": "pnpm build:legacy && pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:types && pnpm build:copy-files", - "build:legacy": "node ../../scripts/build.mjs legacy", + "build": "pnpm build:modern && pnpm build:node && pnpm build:stable && pnpm build:types && pnpm build:copy-files", "build:modern": "echo 'Skip modern build'", "build:node": "node ../../scripts/build.mjs node", "build:stable": "node ../../scripts/build.mjs stable", @@ -36,6 +35,8 @@ }, "dependencies": { "@babel/runtime": "^7.24.4", + "@mui/internal-markdown": "workspace:^", + "clipboard-copy": "^4.0.1", "clsx": "^2.1.0", "nprogress": "^0.2.0", "prop-types": "^15.8.1" diff --git a/packages/mui-docs/src/CodeCopy/CodeCopy.tsx b/packages/mui-docs/src/CodeCopy/CodeCopy.tsx new file mode 100644 index 00000000000000..f39c1adb147380 --- /dev/null +++ b/packages/mui-docs/src/CodeCopy/CodeCopy.tsx @@ -0,0 +1,199 @@ +import * as React from 'react'; +import { useRouter } from 'next/router'; +import clipboardCopy from 'clipboard-copy'; + +const CodeBlockContext = React.createContext>({ + current: null, +}); + +/** + * How to use: spread the handlers to the .MuiCode-root + * + * The html structure should be: + *
+ *
...
+ * + *
+ */ +export function useCodeCopy(): React.HTMLAttributes { + const rootNode = React.useContext(CodeBlockContext); + return { + onMouseEnter: (event) => { + rootNode.current = event.currentTarget; + }, + onMouseLeave: (event) => { + if (rootNode.current === event.currentTarget) { + (rootNode.current.querySelector('.MuiCode-copy') as null | HTMLButtonElement)?.blur(); + rootNode.current = null; + } + }, + onFocus: (event) => { + rootNode.current = event.currentTarget; + }, + onBlur: (event) => { + if (rootNode.current === event.currentTarget) { + rootNode.current = null; + } + }, + }; +} + +function InitCodeCopy() { + const rootNode = React.useContext(CodeBlockContext); + const router = useRouter(); + React.useEffect(() => { + let key = 'Ctrl + '; + if (typeof window !== 'undefined') { + const macOS = window.navigator.platform.toUpperCase().indexOf('MAC') >= 0; + if (macOS) { + key = '⌘'; + } + } + const codeRoots = document.getElementsByClassName( + 'MuiCode-root', + ) as HTMLCollectionOf; + + if (codeRoots !== null) { + const listeners: Array<() => void> = []; + Array.from(codeRoots).forEach((elm) => { + const handleMouseEnter = () => { + rootNode.current = elm; + }; + + elm.addEventListener('mouseenter', handleMouseEnter); + listeners.push(() => elm.removeEventListener('mouseenter', handleMouseEnter)); + + const handleMouseLeave = () => { + if (rootNode.current === elm) { + (rootNode.current.querySelector('.MuiCode-copy') as null | HTMLButtonElement)?.blur(); + rootNode.current = null; + } + }; + elm.addEventListener('mouseleave', handleMouseLeave); + listeners.push(() => elm.removeEventListener('mouseleave', handleMouseLeave)); + + const handleFocusin = () => { + // use `focusin` because it bubbles from the copy button + rootNode.current = elm; + }; + elm.addEventListener('focusin', handleFocusin); + listeners.push(() => elm.removeEventListener('focusin', handleFocusin)); + + const handleFocusout = () => { + // use `focusout` because it bubbles from the copy button + if (rootNode.current === elm) { + rootNode.current = null; + } + }; + elm.addEventListener('focusout', handleFocusout); + listeners.push(() => elm.removeEventListener('focusout', handleFocusout)); + + async function handleClick(event: MouseEvent) { + const trigger = event.currentTarget as HTMLButtonElement; + const pre = (event.currentTarget as Element)?.previousElementSibling as Element; + const textNode = trigger.childNodes[0]; + textNode.nodeValue = textNode.textContent?.replace('Copy', 'Copied') || null; + trigger.dataset.copied = 'true'; + setTimeout(() => { + if (trigger) { + textNode.nodeValue = textNode.textContent?.replace('Copied', 'Copy') || null; + delete trigger.dataset.copied; + } + }, 2000); + try { + if (pre.textContent) { + await clipboardCopy(pre.textContent); + } + // eslint-disable-next-line no-empty + } catch (error) {} + } + + const btn = elm.querySelector('.MuiCode-copy') as HTMLButtonElement | null; + if (btn) { + const keyNode = btn.querySelector('.MuiCode-copyKeypress')?.childNodes[1]; + if (!keyNode) { + // skip the logic if the btn is not generated from the markdown. + return; + } + keyNode.textContent = keyNode?.textContent?.replace('$key', key) || null; + btn.addEventListener('click', handleClick); + listeners.push(() => btn.removeEventListener('click', handleClick)); + } + }); + + return () => { + listeners.forEach((removeEventListener) => { + removeEventListener(); + }); + }; + } + + return undefined; + }, [rootNode, router.pathname]); + return null; +} + +function hasNativeSelection(element: HTMLTextAreaElement) { + if (window.getSelection()?.toString()) { + return true; + } + + // window.getSelection() returns an empty string in Firefox for selections inside a form element. + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=85686. + // Instead, we can use element.selectionStart that is only defined on form elements. + if (element && (element.selectionEnd || 0) - (element.selectionStart || 0) > 0) { + return true; + } + + return false; +} + +interface CodeCopyProviderProps { + children: React.ReactNode; +} + +/** + * Place at the page level. It will check the keydown event and try to initiate copy click if rootNode exist. + * Any code block inside the tree can set the rootNode when mouse enter to leverage keyboard copy. + */ +export function CodeCopyProvider({ children }: CodeCopyProviderProps) { + const rootNode = React.useRef(null); + React.useEffect(() => { + document.addEventListener('keydown', (event) => { + if (!rootNode.current) { + return; + } + + // Skip if user is highlighting a text. + if (hasNativeSelection(event.target as HTMLTextAreaElement)) { + return; + } + + // Skip if it's not a copy keyboard event + if ( + !( + (event.ctrlKey || event.metaKey) && + event.key.toLowerCase() === 'c' && + !event.shiftKey && + !event.altKey + ) + ) { + return; + } + + const copyBtn = rootNode.current.querySelector('.MuiCode-copy') as HTMLButtonElement; + const initialEventAction = copyBtn.getAttribute('data-ga-event-action'); + // update the 'data-ga-event-action' on the button to track keyboard interaction + copyBtn.dataset.gaEventAction = + initialEventAction?.replace('click', 'keyboard') || 'copy-keyboard'; + copyBtn.click(); // let the GA setup in GoogleAnalytics.js do the job + copyBtn.dataset.gaEventAction = initialEventAction!; // reset the 'data-ga-event-action' back to initial + }); + }, []); + return ( + + + {children} + + ); +} diff --git a/packages/mui-docs/src/CodeCopy/CodeCopyButton.tsx b/packages/mui-docs/src/CodeCopy/CodeCopyButton.tsx new file mode 100644 index 00000000000000..648e479a504399 --- /dev/null +++ b/packages/mui-docs/src/CodeCopy/CodeCopyButton.tsx @@ -0,0 +1,41 @@ +import * as React from 'react'; +import ContentCopyRoundedIcon from '@mui/icons-material/ContentCopyRounded'; +import LibraryAddCheckRoundedIcon from '@mui/icons-material/LibraryAddCheckRounded'; +import useClipboardCopy from './useClipboardCopy'; + +export interface CodeCopyButtonProps { + code: string; +} + +export function CodeCopyButton(props: CodeCopyButtonProps) { + const { code, ...other } = props; + const { copy, isCopied } = useClipboardCopy(); + // This component is designed to be wrapped in NoSsr + const macOS = window.navigator.platform.toUpperCase().indexOf('MAC') >= 0; + const key = macOS ? '⌘' : 'Ctrl + '; + + return ( +
+ +
+ ); +} diff --git a/packages/mui-docs/src/CodeCopy/index.tsx b/packages/mui-docs/src/CodeCopy/index.tsx new file mode 100644 index 00000000000000..074604ad8bfd26 --- /dev/null +++ b/packages/mui-docs/src/CodeCopy/index.tsx @@ -0,0 +1,3 @@ +export * from './CodeCopy'; +export * from './CodeCopyButton'; +export { default as useClipboardCopy } from './useClipboardCopy'; diff --git a/packages/mui-docs/src/CodeCopy/useClipboardCopy.ts b/packages/mui-docs/src/CodeCopy/useClipboardCopy.ts new file mode 100644 index 00000000000000..9979a455775ae5 --- /dev/null +++ b/packages/mui-docs/src/CodeCopy/useClipboardCopy.ts @@ -0,0 +1,25 @@ +import * as React from 'react'; +import clipboardCopy from 'clipboard-copy'; + +export default function useClipboardCopy() { + const [isCopied, setIsCopied] = React.useState(false); + const timeout = React.useRef>(); + + React.useEffect( + () => () => { + clearTimeout(timeout.current); + }, + [], + ); + + const copy = async (text: string) => { + await clipboardCopy(text); + setIsCopied(true); + clearTimeout(timeout.current); + timeout.current = setTimeout(() => { + setIsCopied(false); + }, 1200); + }; + + return { copy, isCopied }; +} diff --git a/packages/mui-docs/src/HighlightedCode/HighlightedCode.tsx b/packages/mui-docs/src/HighlightedCode/HighlightedCode.tsx new file mode 100644 index 00000000000000..dd2d43fd020849 --- /dev/null +++ b/packages/mui-docs/src/HighlightedCode/HighlightedCode.tsx @@ -0,0 +1,52 @@ +import * as React from 'react'; +import prism from '@mui/internal-markdown/prism'; +import { NoSsr } from '@mui/base/NoSsr'; +import { ButtonProps } from '@mui/material/Button'; +import { SxProps } from '@mui/material/styles'; +import { useCodeCopy, CodeCopyButton } from '../CodeCopy'; +import { MarkdownElement } from '../MarkdownElement'; + +export interface HighlightedCodeProps { + code: string; + component?: React.ElementType; + copyButtonHidden?: boolean; + copyButtonProps?: ButtonProps; + language: string; + sx?: SxProps; +} + +export const HighlightedCode = React.forwardRef( + function HighlightedCode(props, ref) { + const { + copyButtonHidden = false, + copyButtonProps, + code, + language, + component: Component = MarkdownElement, + ...other + } = props; + const renderedCode = React.useMemo(() => { + return prism(code.trim(), language); + }, [code, language]); + const handlers = useCodeCopy(); + + return ( + +
+ {copyButtonHidden ? null : ( + + + + )} +
+            
+          
+
+
+ ); + }, +); diff --git a/packages/mui-docs/src/HighlightedCode/index.tsx b/packages/mui-docs/src/HighlightedCode/index.tsx new file mode 100644 index 00000000000000..c348a40cdaa7c2 --- /dev/null +++ b/packages/mui-docs/src/HighlightedCode/index.tsx @@ -0,0 +1 @@ +export * from './HighlightedCode'; diff --git a/packages/mui-docs/src/MarkdownElement/MarkdownElement.tsx b/packages/mui-docs/src/MarkdownElement/MarkdownElement.tsx new file mode 100644 index 00000000000000..b95280444c9c0a --- /dev/null +++ b/packages/mui-docs/src/MarkdownElement/MarkdownElement.tsx @@ -0,0 +1,831 @@ +import * as React from 'react'; +import clsx from 'clsx'; +import { alpha, darken, styled } from '@mui/material/styles'; +import { brandingDarkTheme as darkTheme, brandingLightTheme as lightTheme } from '../branding'; + +const Root = styled('div')( + ({ theme }) => ({ + ...lightTheme.typography.body1, + lineHeight: 1.6, // Increased compared to the 1.5 default to make the docs easier to read. + color: `var(--muidocs-palette-text-primary, ${lightTheme.palette.text.primary})`, + '& :focus-visible': { + outline: `3px solid ${alpha(lightTheme.palette.primary[500], 0.5)}`, + outlineOffset: 2, + }, + '& strong': { + color: `var(--muidocs-palette-text-primary, ${lightTheme.palette.text.primary})`, + }, + wordBreak: 'break-word', + '& pre': { + lineHeight: 1.5, // Developers like when the code is dense. + margin: theme.spacing(2, 'auto'), + padding: theme.spacing(2), + backgroundColor: 'hsl(210, 35%, 9%)', // a special, one-off, color tailored for the code blocks using MUI's branding theme blue palette as the starting point. It has a less saturaded color but still maintaining a bit of the blue tint. + color: 'hsl(60, 30%, 96%)', + colorScheme: 'dark', + borderRadius: `var(--muidocs-shape-borderRadius, ${ + theme.shape?.borderRadius ?? lightTheme.shape.borderRadius + }px)`, + border: '1px solid', + borderColor: `var(--muidocs-palette-primaryDark-700, ${lightTheme.palette.primaryDark[700]})`, + overflow: 'auto', + WebkitOverflowScrolling: 'touch', + fontSize: lightTheme.typography.pxToRem(13), + maxWidth: 'calc(100vw - 32px)', + maxHeight: '400px', + [lightTheme.breakpoints.up('md')]: { + maxWidth: 'calc(100vw - 32px - 16px)', + }, + }, + '& code': { + ...lightTheme.typography.body2, + fontFamily: lightTheme.typography.fontFamilyCode, + fontWeight: 400, + WebkitFontSmoothing: 'subpixel-antialiased', + }, + '& pre > code': { + // Reset for Safari + // https://github.com/necolas/normalize.css/blob/master/normalize.css#L102 + fontSize: 'inherit', + }, + // inline code block + '& :not(pre) > code': { + padding: '2px 4px', + color: `var(--muidocs-palette-text-primary, ${lightTheme.palette.text.primary})`, + backgroundColor: `var(--muidocs-palette-grey-50, ${lightTheme.palette.grey[50]})`, + border: '1px solid', + borderColor: `var(--muidocs-palette-grey-200, ${lightTheme.palette.grey[200]})`, + borderRadius: 6, + fontSize: lightTheme.typography.pxToRem(13), + direction: 'ltr /*! @noflip */', + boxDecorationBreak: 'clone', + }, + '& h1': { + ...lightTheme.typography.h3, + fontSize: lightTheme.typography.pxToRem(36), + fontFamily: `"General Sans", ${lightTheme.typography.fontFamilySystem}`, + margin: '10px 0', + color: `var(--muidocs-palette-primaryDark-900, ${lightTheme.palette.primaryDark[900]})`, + fontWeight: 600, + letterSpacing: -0.2, + }, + '& .description': { + ...lightTheme.typography.subtitle1, + fontWeight: 400, + margin: '0 0 24px', + }, + '& .component-tabs': { + margin: '0 0 40px', + }, + '& h2': { + ...lightTheme.typography.h5, + fontFamily: `"General Sans", ${lightTheme.typography.fontFamilySystem}`, + fontSize: theme.typography.pxToRem(26), + fontWeight: lightTheme.typography.fontWeightSemiBold, + color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, + margin: '40px 0 4px', + }, + '& h3': { + ...lightTheme.typography.h6, + fontFamily: `"General Sans", ${lightTheme.typography.fontFamilySystem}`, + fontSize: theme.typography.pxToRem(20), + fontWeight: lightTheme.typography.fontWeightSemiBold, + color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, + margin: '24px 0 4px', + }, + '& h4': { + ...lightTheme.typography.subtitle1, + fontFamily: `"General Sans", ${lightTheme.typography.fontFamilySystem}`, + fontWeight: lightTheme.typography.fontWeightSemiBold, + color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, + margin: '20px 0 6px', + }, + '& h5': { + ...lightTheme.typography.subtitle2, + fontFamily: `"General Sans", ${lightTheme.typography.fontFamilySystem}`, + fontWeight: lightTheme.typography.fontWeightSemiBold, + color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, + margin: '20px 0 8px', + }, + '& p': { + marginTop: 0, + marginBottom: 16, + color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, + }, + '& ul, & ol': { + paddingLeft: 30, + marginTop: 0, + marginBottom: 16, + '& ul, & ol': { + marginBottom: 6, + }, + }, + '& h1, & h2, & h3, & h4': { + display: 'flex', + alignItems: 'center', + gap: 6, + '& code': { + fontSize: 'inherit', + lineHeight: 'inherit', + // Remove scroll on small screens. + wordBreak: 'break-all', + }, + '& .title-link-to-anchor': { + color: 'inherit', + textDecoration: 'none', + position: 'relative', + display: 'flex', + alignItems: 'center', + }, + '& .anchor-icon': { + // To prevent the link to get the focus. + display: 'inline-flex', + alignItems: 'center', + visibility: 'hidden', + }, + '& a:not(.title-link-to-anchor):hover': { + color: 'currentColor', + border: 'none', + boxShadow: '0 1px 0 0 currentColor', + textDecoration: 'none', + }, + '& .anchor-icon, & .comment-link': { + padding: 0, + cursor: 'pointer', + alignItems: 'center', + justifyContent: 'center', + flexShrink: 0, + textAlign: 'center', + marginLeft: 8, + height: 26, + width: 26, + backgroundColor: `var(--muidocs-palette-primary-50, ${lightTheme.palette.grey[50]})`, + color: `var(--muidocs-palette-grey-600, ${lightTheme.palette.grey[600]})`, + border: '1px solid', + borderColor: `var(--muidocs-palette-divider, ${lightTheme.palette.divider})`, + borderRadius: 8, + '&:hover': { + backgroundColor: alpha(lightTheme.palette.primary[100], 0.4), + borderColor: `var(--muidocs-palette-primary-100, ${lightTheme.palette.primary[100]})`, + color: `var(--muidocs-palette-primary-main, ${lightTheme.palette.primary.main})`, + }, + '& svg': { + height: 14, + width: 14, + fill: 'currentColor', + pointerEvents: 'none', + verticalAlign: 'middle', + }, + }, + '&:hover .anchor-icon': { + visibility: 'visible', + }, + '& .comment-link': { + display: 'none', // So we can have the comment button opt-in. + marginLeft: 'auto', + transition: theme.transitions.create('opacity', { + duration: theme.transitions.duration.shortest, + }), + '& svg': { + fill: 'currentColor', + marginRight: 1.5, + }, + }, + }, + '& h1 code, & h2 code, & h3 code': { + color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, + }, + '& h1 code': { + fontWeight: lightTheme.typography.fontWeightSemiBold, + }, + '& h2 code': { + fontSize: lightTheme.typography.pxToRem(24), + fontWeight: lightTheme.typography.fontWeightSemiBold, + }, + '& h3 code': { + fontSize: lightTheme.typography.pxToRem(18), + }, + '& table': { + // Trade display table for scroll overflow + display: 'block', + wordBreak: 'normal', + overflowX: 'auto', + WebkitOverflowScrolling: 'touch', + borderCollapse: 'collapse', + marginBottom: '20px', + borderSpacing: 0, + '& .prop-name, & .prop-type, & .prop-default, & .slot-name, & .slot-defaultClass, & .slot-default': + { + fontWeight: 400, + fontFamily: lightTheme.typography.fontFamilyCode, + WebkitFontSmoothing: 'subpixel-antialiased', + fontSize: lightTheme.typography.pxToRem(13), + }, + '& .required': { + color: '#006500', + }, + '& .optional': { + color: '#45529f', + }, + '& .prop-type, & .slot-defaultClass': { + color: '#932981', + }, + '& .prop-default, & .slot-default': { + borderBottom: `1px dotted var(--muidocs-palette-divider, ${lightTheme.palette.divider})`, + }, + }, + '& td': { + ...theme.typography.body2, + borderBottom: `1px solid var(--muidocs-palette-divider, ${lightTheme.palette.divider})`, + paddingRight: 20, + paddingTop: 16, + paddingBottom: 16, + color: `var(--muidocs-palette-text-secondary, ${lightTheme.palette.text.secondary})`, + }, + '& td code': { + lineHeight: 1.6, + }, + '& th': { + fontSize: theme.typography.pxToRem(14), + lineHeight: theme.typography.pxToRem(24), + fontWeight: 500, + color: `var(--muidocs-palette-text-primary, ${lightTheme.palette.text.primary})`, + whiteSpace: 'pre', + borderBottom: `1px solid var(--muidocs-palette-divider, ${lightTheme.palette.divider})`, + paddingRight: 20, + paddingTop: 12, + paddingBottom: 12, + }, + '& blockquote': { + position: 'relative', + padding: '0 16px', + margin: 0, + borderLeft: '1.5px solid', + borderColor: `var(--muidocs-palette-grey-200, ${lightTheme.palette.grey[200]})`, + '& p': { + fontSize: theme.typography.pxToRem(12.5), + fontFamily: lightTheme.typography.fontFamilyCode, + fontWeight: lightTheme.typography.fontWeightMedium, + lineHeight: theme.typography.pxToRem(24), + textIndent: 20, + }, + '&::before': { + position: 'absolute', + // eslint-disable-next-line material-ui/straight-quotes + content: '"“"', + color: `var(--muidocs-palette-grey-300, ${lightTheme.palette.grey[300]})`, + fontSize: '2.5rem', + top: 8, + marginLeft: -6, + lineHeight: 0.5, + }, + }, + '& .MuiCallout-root': { + display: 'flex', + gap: 12, + padding: '16px', + margin: '16px 0', + border: '1px solid', + color: `var(--muidocs-palette-text-secondary, ${lightTheme.palette.text.secondary})`, + borderColor: `var(--muidocs-palette-grey-100, ${lightTheme.palette.grey[100]})`, + borderRadius: `var(--muidocs-shape-borderRadius, ${ + theme.shape?.borderRadius ?? lightTheme.shape.borderRadius + }px)`, + '& > code': { + height: 'fit-content', + backgroundColor: `var(--muidocs-palette-grey-100, ${lightTheme.palette.grey[100]})`, + borderColor: `var(--muidocs-palette-grey-300, ${lightTheme.palette.grey[300]})`, + }, + '& .MuiCallout-content': { + minWidth: 0, // Allows content to shrink. Useful when callout contains code block + flexGrow: 1, + '& > p:last-child, & > ul:last-child': { + // Avoid margin on last child + marginBottom: 0, + }, + '& .MuiCode-root': { + '& > pre': { + margin: 0, + marginTop: 4, + }, + }, + '& > ul': { + // Because of the gap left by the icon, we visually need less padding + paddingLeft: 22, + }, + }, + '& > svg': { + marginTop: 2, + width: 20, + height: 20, + flexShrink: 0, + }, + '& > ul, & > p': { + '&:last-child': { + margin: 0, + }, + }, + '& ul, li, p': { + color: 'inherit', + }, + '&.MuiCallout-error': { + color: `var(--muidocs-palette-error-900, ${lightTheme.palette.error[900]})`, + backgroundColor: `var(--muidocs-palette-error-50, ${lightTheme.palette.error[50]})`, + borderColor: `var(--muidocs-palette-error-100, ${lightTheme.palette.error[100]})`, + '& strong': { + color: `var(--muidocs-palette-error-800, ${lightTheme.palette.error[800]})`, + }, + '& > svg': { + fill: `var(--muidocs-palette-error-500, ${lightTheme.palette.error[600]})`, + }, + '& a': { + color: `var(--muidocs-palette-error-800, ${lightTheme.palette.error[800]})`, + textDecorationColor: alpha(lightTheme.palette.error.main, 0.4), + '&:hover': { + textDecorationColor: 'inherit', + }, + }, + }, + '&.MuiCallout-info': { + color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, + backgroundColor: `var(--muidocs-palette-grey-50, ${lightTheme.palette.grey[50]})`, + borderColor: `var(--muidocs-palette-grey-100, ${lightTheme.palette.grey[100]})`, + '& strong': { + color: `var(--muidocs-palette-primary-800, ${lightTheme.palette.primary[800]})`, + }, + '& > svg': { + fill: `var(--muidocs-palette-grey-600, ${lightTheme.palette.grey[600]})`, + }, + }, + '&.MuiCallout-success': { + color: `var(--muidocs-palette-success-900, ${lightTheme.palette.success[900]})`, + backgroundColor: `var(--muidocs-palette-success-50, ${lightTheme.palette.success[50]})`, + borderColor: `var(--muidocs-palette-success-100, ${lightTheme.palette.success[100]})`, + '& strong': { + color: `var(--muidocs-palette-success-900, ${lightTheme.palette.success[900]})`, + }, + '& > svg': { + fill: `var(--muidocs-palette-success-600, ${lightTheme.palette.success[600]})`, + }, + '& a': { + color: `var(--muidocs-palette-success-900, ${lightTheme.palette.success[900]})`, + textDecorationColor: alpha(lightTheme.palette.success.main, 0.4), + '&:hover': { + textDecorationColor: 'inherit', + }, + }, + }, + '&.MuiCallout-warning': { + color: `var(--muidocs-palette-grey-900, ${lightTheme.palette.grey[900]})`, + backgroundColor: alpha(lightTheme.palette.warning[50], 0.5), + borderColor: alpha(lightTheme.palette.warning[700], 0.15), + '& strong': { + color: `var(--muidocs-palette-warning-800, ${lightTheme.palette.warning[800]})`, + }, + '& > svg': { + fill: `var(--muidocs-palette-warning-600, ${lightTheme.palette.warning[600]})`, + }, + '& a': { + color: `var(--muidocs-palette-warning-800, ${lightTheme.palette.warning[800]})`, + textDecorationColor: alpha(lightTheme.palette.warning.main, 0.4), + '&:hover': { + textDecorationColor: 'inherit', + }, + }, + }, + }, + '& a[target="_blank"]::after': { + content: '""', + maskImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' focusable='false' aria-hidden='true' viewBox='0 0 24 24' fill='currentColor'%3E%3Cpath d='M6 6v2h8.59L5 17.59 6.41 19 16 9.41V18h2V6z'%3E%3C/path%3E%3C/svg%3E")`, + display: 'inline-flex', + width: '1em', + height: '1em', + color: 'inherit', + backgroundColor: 'currentColor', + transform: 'translate(0, 2px)', + transition: 'transform 0.3s cubic-bezier(0.1, 0.8, 0.3, 1)', // bounce effect + opacity: 0.8, + }, + '& a[target="_blank"]:hover::after': { + opacity: 1, + transform: 'translate(1px, 0)', + }, + '& a.remove-link-arrow::after': { + // Allows to remove link arrows for images + display: 'none', + }, + '& .Ad-root a::after': { + // Remove link arrow for ads + display: 'none', + }, + '& a:not(.title-link-to-anchor), & a:not(.title-link-to-anchor) code': { + // Style taken from the Link component + color: `var(--muidocs-palette-primary-600, ${lightTheme.palette.primary[600]})`, + fontWeight: theme.typography.fontWeightMedium, + textDecoration: 'underline', + textDecorationColor: alpha(lightTheme.palette.primary.main, 0.4), + '&:hover': { + textDecorationColor: 'inherit', + }, + }, + '& a code': { + color: darken(lightTheme.palette.primary.main, 0.04), + }, + '& a:not(.title-link-to-anchor) code': { + color: darken(lightTheme.palette.primary.main, 0.2), + }, + '& img, & video': { + // Use !important so that inline style on or