From c42535314eb6ab75dee039c164b78ee16478a3a4 Mon Sep 17 00:00:00 2001 From: povilass Date: Tue, 23 Feb 2021 15:06:46 +0200 Subject: [PATCH] [Modal] Migrate to emotion + unstyled (#24857) --- .stylelintrc.js | 1 + docs/pages/api-docs/backdrop-unstyled.json | 2 +- docs/pages/api-docs/backdrop.json | 2 +- docs/pages/api-docs/badge-unstyled.json | 2 +- docs/pages/api-docs/badge.json | 2 +- docs/pages/api-docs/modal-unstyled.js | 23 + docs/pages/api-docs/modal-unstyled.json | 40 ++ docs/pages/api-docs/modal.json | 14 +- docs/pages/api-docs/slider-unstyled.json | 2 +- docs/pages/api-docs/slider.json | 2 +- .../pages/components/badges/UnstyledBadge.js | 3 + .../pages/components/badges/UnstyledBadge.tsx | 3 + docs/src/pages/components/badges/badges.md | 7 + docs/src/pages/components/modal/BasicModal.js | 28 +- .../src/pages/components/modal/BasicModal.tsx | 28 +- .../components/modal/KeepMountedModal.js | 71 ++- .../components/modal/KeepMountedModal.tsx | 73 ++- .../pages/components/modal/ModalUnstyled.js | 64 +++ .../pages/components/modal/ModalUnstyled.tsx | 64 +++ .../src/pages/components/modal/NestedModal.js | 13 +- .../pages/components/modal/NestedModal.tsx | 13 +- .../src/pages/components/modal/ServerModal.js | 75 ++-- .../pages/components/modal/ServerModal.tsx | 77 ++-- .../src/pages/components/modal/SpringModal.js | 60 ++- .../pages/components/modal/SpringModal.tsx | 62 ++- .../components/modal/TransitionsModal.js | 60 ++- .../components/modal/TransitionsModal.tsx | 62 ++- docs/src/pages/components/modal/modal.md | 21 +- docs/src/pages/components/slider/slider.md | 7 + .../speed-dial/ControlledOpenSpeedDial.js | 10 +- .../speed-dial/ControlledOpenSpeedDial.tsx | 10 +- .../speed-dial/SpeedDialTooltipOpen.js | 10 +- .../speed-dial/SpeedDialTooltipOpen.tsx | 10 +- docs/src/pagesApi.js | 1 + .../modal-unstyled/modal-unstyled-de.json | 33 ++ .../modal-unstyled/modal-unstyled-es.json | 33 ++ .../modal-unstyled/modal-unstyled-fr.json | 33 ++ .../modal-unstyled/modal-unstyled-ja.json | 33 ++ .../modal-unstyled/modal-unstyled-pt.json | 33 ++ .../modal-unstyled/modal-unstyled-ru.json | 33 ++ .../modal-unstyled/modal-unstyled-zh.json | 33 ++ .../modal-unstyled/modal-unstyled.json | 33 ++ docs/translations/api-docs/modal/modal.json | 16 +- .../BackdropUnstyled/BackdropUnstyled.d.ts | 1 - .../src/BackdropUnstyled/BackdropUnstyled.js | 11 +- .../src/BadgeUnstyled/BadgeUnstyled.d.ts | 1 - .../src/BadgeUnstyled/BadgeUnstyled.js | 6 +- .../src/ModalUnstyled}/ModalManager.test.js | 2 +- .../src/ModalUnstyled}/ModalManager.ts | 8 +- .../src/ModalUnstyled/ModalUnstyled.d.ts | 175 ++++++++ .../src/ModalUnstyled/ModalUnstyled.js | 419 ++++++++++++++++++ .../src/ModalUnstyled/ModalUnstyled.test.js | 75 ++++ .../src/ModalUnstyled/index.d.ts | 8 + .../src/ModalUnstyled/index.js | 5 + .../ModalUnstyled/modalUnstyledClasses.d.ts | 9 + .../src/ModalUnstyled/modalUnstyledClasses.js | 10 + .../src/SliderUnstyled/SliderUnstyled.d.ts | 1 - .../src/SliderUnstyled/SliderUnstyled.js | 33 +- packages/material-ui-unstyled/src/index.d.ts | 3 + packages/material-ui-unstyled/src/index.js | 3 + .../material-ui/src/Backdrop/Backdrop.d.ts | 1 - packages/material-ui/src/Backdrop/Backdrop.js | 11 +- packages/material-ui/src/Badge/Badge.d.ts | 1 - packages/material-ui/src/Badge/Badge.js | 5 +- packages/material-ui/src/Modal/Modal.d.ts | 142 ++---- packages/material-ui/src/Modal/Modal.js | 314 +++++-------- packages/material-ui/src/Modal/Modal.test.js | 20 +- .../material-ui/src/Modal/SimpleBackdrop.js | 54 --- packages/material-ui/src/Modal/index.d.ts | 4 +- packages/material-ui/src/Modal/index.js | 4 +- packages/material-ui/src/Slider/Slider.d.ts | 1 - packages/material-ui/src/Slider/Slider.js | 1 - .../material-ui/src/styles/components.d.ts | 4 + .../material-ui/src/styles/overrides.d.ts | 2 + 74 files changed, 1701 insertions(+), 835 deletions(-) create mode 100644 docs/pages/api-docs/modal-unstyled.js create mode 100644 docs/pages/api-docs/modal-unstyled.json create mode 100644 docs/src/pages/components/modal/ModalUnstyled.js create mode 100644 docs/src/pages/components/modal/ModalUnstyled.tsx create mode 100644 docs/translations/api-docs/modal-unstyled/modal-unstyled-de.json create mode 100644 docs/translations/api-docs/modal-unstyled/modal-unstyled-es.json create mode 100644 docs/translations/api-docs/modal-unstyled/modal-unstyled-fr.json create mode 100644 docs/translations/api-docs/modal-unstyled/modal-unstyled-ja.json create mode 100644 docs/translations/api-docs/modal-unstyled/modal-unstyled-pt.json create mode 100644 docs/translations/api-docs/modal-unstyled/modal-unstyled-ru.json create mode 100644 docs/translations/api-docs/modal-unstyled/modal-unstyled-zh.json create mode 100644 docs/translations/api-docs/modal-unstyled/modal-unstyled.json rename packages/{material-ui/src/Modal => material-ui-unstyled/src/ModalUnstyled}/ModalManager.test.js (99%) rename packages/{material-ui/src/Modal => material-ui-unstyled/src/ModalUnstyled}/ModalManager.ts (97%) create mode 100644 packages/material-ui-unstyled/src/ModalUnstyled/ModalUnstyled.d.ts create mode 100644 packages/material-ui-unstyled/src/ModalUnstyled/ModalUnstyled.js create mode 100644 packages/material-ui-unstyled/src/ModalUnstyled/ModalUnstyled.test.js create mode 100644 packages/material-ui-unstyled/src/ModalUnstyled/index.d.ts create mode 100644 packages/material-ui-unstyled/src/ModalUnstyled/index.js create mode 100644 packages/material-ui-unstyled/src/ModalUnstyled/modalUnstyledClasses.d.ts create mode 100644 packages/material-ui-unstyled/src/ModalUnstyled/modalUnstyledClasses.js delete mode 100644 packages/material-ui/src/Modal/SimpleBackdrop.js diff --git a/.stylelintrc.js b/.stylelintrc.js index 12f7a1c2197b6e..291948472baa26 100644 --- a/.stylelintrc.js +++ b/.stylelintrc.js @@ -13,5 +13,6 @@ module.exports = { 'no-missing-end-of-source-newline': null, 'declaration-colon-newline-after': null, 'value-keyword-case': null, + 'value-list-comma-newline-after': null, // not compatible with prettier }, }; diff --git a/docs/pages/api-docs/backdrop-unstyled.json b/docs/pages/api-docs/backdrop-unstyled.json index e7965f286d0042..9bbb19400372f2 100644 --- a/docs/pages/api-docs/backdrop-unstyled.json +++ b/docs/pages/api-docs/backdrop-unstyled.json @@ -1,7 +1,7 @@ { "props": { "children": { "type": { "name": "node" } }, - "classes": { "type": { "name": "object" }, "default": "{}" }, + "classes": { "type": { "name": "object" } }, "component": { "type": { "name": "elementType" } }, "components": { "type": { "name": "shape", "description": "{ Root?: elementType }" }, diff --git a/docs/pages/api-docs/backdrop.json b/docs/pages/api-docs/backdrop.json index aa046e5310dee0..1b7e0f112ddfbe 100644 --- a/docs/pages/api-docs/backdrop.json +++ b/docs/pages/api-docs/backdrop.json @@ -2,7 +2,7 @@ "props": { "open": { "type": { "name": "bool" }, "required": true }, "children": { "type": { "name": "node" } }, - "classes": { "type": { "name": "object" }, "default": "{}" }, + "classes": { "type": { "name": "object" } }, "component": { "type": { "name": "elementType" } }, "components": { "type": { "name": "shape", "description": "{ Root?: elementType }" }, diff --git a/docs/pages/api-docs/badge-unstyled.json b/docs/pages/api-docs/badge-unstyled.json index fc342d6fdc44c9..d71b77b33ff8c6 100644 --- a/docs/pages/api-docs/badge-unstyled.json +++ b/docs/pages/api-docs/badge-unstyled.json @@ -9,7 +9,7 @@ }, "badgeContent": { "type": { "name": "node" } }, "children": { "type": { "name": "node" } }, - "classes": { "type": { "name": "object" }, "default": "{}" }, + "classes": { "type": { "name": "object" } }, "component": { "type": { "name": "elementType" } }, "components": { "type": { "name": "shape", "description": "{ Badge?: elementType, Root?: elementType }" }, diff --git a/docs/pages/api-docs/badge.json b/docs/pages/api-docs/badge.json index 942beae3a8af4e..700a75dd7833bb 100644 --- a/docs/pages/api-docs/badge.json +++ b/docs/pages/api-docs/badge.json @@ -9,7 +9,7 @@ }, "badgeContent": { "type": { "name": "node" } }, "children": { "type": { "name": "node" } }, - "classes": { "type": { "name": "object" }, "default": "{}" }, + "classes": { "type": { "name": "object" } }, "color": { "type": { "name": "union", diff --git a/docs/pages/api-docs/modal-unstyled.js b/docs/pages/api-docs/modal-unstyled.js new file mode 100644 index 00000000000000..ace2b24794a016 --- /dev/null +++ b/docs/pages/api-docs/modal-unstyled.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import ApiPage from 'docs/src/modules/components/ApiPage'; +import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; +import jsonPageContent from './modal-unstyled.json'; + +export default function Page(props) { + const { descriptions, pageContent } = props; + return ; +} + +Page.getInitialProps = () => { + const req = require.context( + 'docs/translations/api-docs/modal-unstyled', + false, + /modal-unstyled.*.json$/, + ); + const descriptions = mapApiPageTranslations(req); + + return { + descriptions, + pageContent: jsonPageContent, + }; +}; diff --git a/docs/pages/api-docs/modal-unstyled.json b/docs/pages/api-docs/modal-unstyled.json new file mode 100644 index 00000000000000..88384b96432177 --- /dev/null +++ b/docs/pages/api-docs/modal-unstyled.json @@ -0,0 +1,40 @@ +{ + "props": { + "children": { "type": { "name": "custom", "description": "element" }, "required": true }, + "open": { "type": { "name": "bool" }, "required": true }, + "BackdropComponent": { "type": { "name": "elementType" } }, + "BackdropProps": { "type": { "name": "object" } }, + "classes": { "type": { "name": "object" } }, + "closeAfterTransition": { "type": { "name": "bool" } }, + "component": { "type": { "name": "elementType" } }, + "components": { + "type": { "name": "shape", "description": "{ Root?: elementType }" }, + "default": "{}" + }, + "componentsProps": { "type": { "name": "object" }, "default": "{}" }, + "container": { "type": { "name": "union", "description": "HTML element
| func" } }, + "disableAutoFocus": { "type": { "name": "bool" } }, + "disableEnforceFocus": { "type": { "name": "bool" } }, + "disableEscapeKeyDown": { "type": { "name": "bool" } }, + "disablePortal": { "type": { "name": "bool" } }, + "disableRestoreFocus": { "type": { "name": "bool" } }, + "disableScrollLock": { "type": { "name": "bool" } }, + "hideBackdrop": { "type": { "name": "bool" } }, + "keepMounted": { "type": { "name": "bool" } }, + "onBackdropClick": { "type": { "name": "func" } }, + "onClose": { "type": { "name": "func" } } + }, + "name": "ModalUnstyled", + "styles": { + "classes": ["root", "hidden"], + "globalClasses": { "root": "MuiModal-root", "hidden": "MuiModal-hidden" }, + "name": null + }, + "spread": true, + "forwardsRefTo": "HTMLDivElement", + "filename": "/packages/material-ui-unstyled/src/ModalUnstyled/ModalUnstyled.js", + "inheritance": null, + "demos": "", + "styledComponent": true, + "cssComponent": false +} diff --git a/docs/pages/api-docs/modal.json b/docs/pages/api-docs/modal.json index 9bd8a192586a86..22d06f7d84fed9 100644 --- a/docs/pages/api-docs/modal.json +++ b/docs/pages/api-docs/modal.json @@ -2,9 +2,16 @@ "props": { "children": { "type": { "name": "custom", "description": "element" }, "required": true }, "open": { "type": { "name": "bool" }, "required": true }, - "BackdropComponent": { "type": { "name": "elementType" }, "default": "SimpleBackdrop" }, + "BackdropComponent": { "type": { "name": "elementType" }, "default": "Backdrop" }, "BackdropProps": { "type": { "name": "object" } }, + "classes": { "type": { "name": "object" } }, "closeAfterTransition": { "type": { "name": "bool" } }, + "component": { "type": { "name": "elementType" } }, + "components": { + "type": { "name": "shape", "description": "{ Root?: elementType }" }, + "default": "{}" + }, + "componentsProps": { "type": { "name": "object" }, "default": "{}" }, "container": { "type": { "name": "union", "description": "HTML element
| func" } }, "disableAutoFocus": { "type": { "name": "bool" } }, "disableEnforceFocus": { "type": { "name": "bool" } }, @@ -15,10 +22,11 @@ "hideBackdrop": { "type": { "name": "bool" } }, "keepMounted": { "type": { "name": "bool" } }, "onBackdropClick": { "type": { "name": "func" } }, - "onClose": { "type": { "name": "func" } } + "onClose": { "type": { "name": "func" } }, + "sx": { "type": { "name": "object" } } }, "name": "Modal", - "styles": { "classes": [], "globalClasses": {}, "name": null }, + "styles": { "classes": ["root", "hidden"], "globalClasses": {}, "name": "MuiModal" }, "spread": true, "forwardsRefTo": "HTMLDivElement", "filename": "/packages/material-ui/src/Modal/Modal.js", diff --git a/docs/pages/api-docs/slider-unstyled.json b/docs/pages/api-docs/slider-unstyled.json index c9a79c141d02c9..75d95a1e0c9722 100644 --- a/docs/pages/api-docs/slider-unstyled.json +++ b/docs/pages/api-docs/slider-unstyled.json @@ -3,7 +3,7 @@ "aria-label": { "type": { "name": "custom", "description": "string" } }, "aria-labelledby": { "type": { "name": "string" } }, "aria-valuetext": { "type": { "name": "custom", "description": "string" } }, - "classes": { "type": { "name": "object" }, "default": "{}" }, + "classes": { "type": { "name": "object" } }, "component": { "type": { "name": "elementType" } }, "components": { "type": { diff --git a/docs/pages/api-docs/slider.json b/docs/pages/api-docs/slider.json index a1208617183d9b..e3cf3afdd99055 100644 --- a/docs/pages/api-docs/slider.json +++ b/docs/pages/api-docs/slider.json @@ -3,7 +3,7 @@ "aria-label": { "type": { "name": "custom", "description": "string" } }, "aria-labelledby": { "type": { "name": "string" } }, "aria-valuetext": { "type": { "name": "custom", "description": "string" } }, - "classes": { "type": { "name": "object" }, "default": "{}" }, + "classes": { "type": { "name": "object" } }, "color": { "type": { "name": "enum", "description": "'primary'
| 'secondary'" }, "default": "'primary'" diff --git a/docs/src/pages/components/badges/UnstyledBadge.js b/docs/src/pages/components/badges/UnstyledBadge.js index db2b319077c072..0c95d7428c80e7 100644 --- a/docs/src/pages/components/badges/UnstyledBadge.js +++ b/docs/src/pages/components/badges/UnstyledBadge.js @@ -12,6 +12,9 @@ const StyledBadge = styled(BadgeUnstyled)` font-variant: tabular-nums; list-style: none; font-feature-settings: 'tnum'; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', + 'Segoe UI Symbol'; position: relative; display: inline-block; line-height: 1; diff --git a/docs/src/pages/components/badges/UnstyledBadge.tsx b/docs/src/pages/components/badges/UnstyledBadge.tsx index db2b319077c072..0c95d7428c80e7 100644 --- a/docs/src/pages/components/badges/UnstyledBadge.tsx +++ b/docs/src/pages/components/badges/UnstyledBadge.tsx @@ -12,6 +12,9 @@ const StyledBadge = styled(BadgeUnstyled)` font-variant: tabular-nums; list-style: none; font-feature-settings: 'tnum'; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', + 'Segoe UI Symbol'; position: relative; display: inline-block; line-height: 1; diff --git a/docs/src/pages/components/badges/badges.md b/docs/src/pages/components/badges/badges.md index 51f7b3d140e3a7..3174d04527d18f 100644 --- a/docs/src/pages/components/badges/badges.md +++ b/docs/src/pages/components/badges/badges.md @@ -58,4 +58,11 @@ You can use the `anchorOrigin` prop to move the badge to any corner of the wrapp ## Unstyled badge +The badge also comes with an unstyled version. +It's ideal for doing heavy customizations and minimizing bundle size. + +```js +import BadgeUnstyled from '@material-ui/unstyled/BadgeUnstyled'; +``` + {{"demo": "pages/components/badges/UnstyledBadge.js"}} diff --git a/docs/src/pages/components/modal/BasicModal.js b/docs/src/pages/components/modal/BasicModal.js index a87295966edd72..ed927bd3319a08 100644 --- a/docs/src/pages/components/modal/BasicModal.js +++ b/docs/src/pages/components/modal/BasicModal.js @@ -1,5 +1,7 @@ import * as React from 'react'; import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import Typography from '@material-ui/core/Typography'; import Modal from '@material-ui/core/Modal'; const style = { @@ -11,27 +13,17 @@ const style = { bgcolor: 'background.paper', border: '2px solid #000', boxShadow: 24, - pt: 2, - px: 4, - pb: 3, + p: 4, }; export default function BasicModal() { const [open, setOpen] = React.useState(false); - - const handleOpen = () => { - setOpen(true); - }; - - const handleClose = () => { - setOpen(false); - }; + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); return (
- + - - +
diff --git a/docs/src/pages/components/modal/BasicModal.tsx b/docs/src/pages/components/modal/BasicModal.tsx index f792e37f575e71..1fc108be8c984f 100644 --- a/docs/src/pages/components/modal/BasicModal.tsx +++ b/docs/src/pages/components/modal/BasicModal.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import Typography from '@material-ui/core/Typography'; import Modal from '@material-ui/core/Modal'; const style = { @@ -11,27 +13,17 @@ const style = { bgcolor: 'background.paper', border: '2px solid #000', boxShadow: 24, - pt: 2, - px: 4, - pb: 3, + p: 4, }; export default function BasicModal() { const [open, setOpen] = React.useState(false); - - const handleOpen = () => { - setOpen(true); - }; - - const handleClose = () => { - setOpen(false); - }; + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); return (
- + - - +
diff --git a/docs/src/pages/components/modal/KeepMountedModal.js b/docs/src/pages/components/modal/KeepMountedModal.js index a4846043487880..d021761291834f 100644 --- a/docs/src/pages/components/modal/KeepMountedModal.js +++ b/docs/src/pages/components/modal/KeepMountedModal.js @@ -1,52 +1,29 @@ import * as React from 'react'; -import { makeStyles } from '@material-ui/core/styles'; +import Box from '@material-ui/core/Box'; import Modal from '@material-ui/core/Modal'; - -function rand() { - return Math.round(Math.random() * 20) - 10; -} - -function getModalStyle() { - const top = 50 + rand(); - const left = 50 + rand(); - - return { - top: `${top}%`, - left: `${left}%`, - transform: `translate(-${top}%, -${left}%)`, - }; -} - -const useStyles = makeStyles((theme) => ({ - paper: { - position: 'absolute', - width: 400, - backgroundColor: theme.palette.background.paper, - border: '2px solid #000', - boxShadow: theme.shadows[5], - padding: theme.spacing(2, 4, 3), - }, -})); +import Button from '@material-ui/core/Button'; +import Typography from '@material-ui/core/Typography'; + +const style = { + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: 400, + bgcolor: 'background.paper', + border: '2px solid #000', + boxShadow: 24, + p: 4, +}; export default function KeepMountedModal() { - const classes = useStyles(); - // getModalStyle is not a pure function, we roll the style only on the first render - const [modalStyle] = React.useState(getModalStyle); const [open, setOpen] = React.useState(false); - - const handleOpen = () => { - setOpen(true); - }; - - const handleClose = () => { - setOpen(false); - }; + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); return (
- + -
-

Text in a modal

-

+ + + Text in a modal + + Duis mollis, est non commodo luctus, nisi erat porttitor ligula. -

-
+ +
); diff --git a/docs/src/pages/components/modal/KeepMountedModal.tsx b/docs/src/pages/components/modal/KeepMountedModal.tsx index 8289849b26a41a..348c39b6412d71 100644 --- a/docs/src/pages/components/modal/KeepMountedModal.tsx +++ b/docs/src/pages/components/modal/KeepMountedModal.tsx @@ -1,54 +1,29 @@ import * as React from 'react'; -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'; +import Box from '@material-ui/core/Box'; import Modal from '@material-ui/core/Modal'; - -function rand() { - return Math.round(Math.random() * 20) - 10; -} - -function getModalStyle() { - const top = 50 + rand(); - const left = 50 + rand(); - - return { - top: `${top}%`, - left: `${left}%`, - transform: `translate(-${top}%, -${left}%)`, - }; -} - -const useStyles = makeStyles((theme: Theme) => - createStyles({ - paper: { - position: 'absolute', - width: 400, - backgroundColor: theme.palette.background.paper, - border: '2px solid #000', - boxShadow: theme.shadows[5], - padding: theme.spacing(2, 4, 3), - }, - }), -); +import Button from '@material-ui/core/Button'; +import Typography from '@material-ui/core/Typography'; + +const style = { + position: 'absolute' as 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: 400, + bgcolor: 'background.paper', + border: '2px solid #000', + boxShadow: 24, + p: 4, +}; export default function KeepMountedModal() { - const classes = useStyles(); - // getModalStyle is not a pure function, we roll the style only on the first render - const [modalStyle] = React.useState(getModalStyle); const [open, setOpen] = React.useState(false); - - const handleOpen = () => { - setOpen(true); - }; - - const handleClose = () => { - setOpen(false); - }; + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); return (
- + -
-

Text in a modal

-

+ + + Text in a modal + + Duis mollis, est non commodo luctus, nisi erat porttitor ligula. -

-
+ +
); diff --git a/docs/src/pages/components/modal/ModalUnstyled.js b/docs/src/pages/components/modal/ModalUnstyled.js new file mode 100644 index 00000000000000..7956a3008ffa09 --- /dev/null +++ b/docs/src/pages/components/modal/ModalUnstyled.js @@ -0,0 +1,64 @@ +import * as React from 'react'; +import { experimentalStyled as styled } from '@material-ui/core/styles'; +import Box from '@material-ui/core/Box'; +import ModalUnstyled from '@material-ui/unstyled/ModalUnstyled'; + +const StyledModal = styled(ModalUnstyled)` + position: fixed; + z-index: 1300; + right: 0; + bottom: 0; + top: 0; + left: 0; + display: flex; + align-items: center; + justify-content: center; +`; + +const Backdrop = styled('div')` + z-index: -1; + position: fixed; + right: 0; + bottom: 0; + top: 0; + left: 0; + background-color: rgba(0, 0, 0, 0.5); + -webkit-tap-highlight-color: transparent; +`; + +const style = { + width: 400, + bgcolor: 'background.paper', + border: '2px solid #000', + p: 2, + px: 4, + pb: 3, +}; + +export default function ModalUnstyledDemo() { + const [open, setOpen] = React.useState(false); + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); + + return ( +
+ + + +

Text in a modal

+

+ Aliquid amet deserunt earum eos nihil officia porro, quasi quibusdam! +

+
+
+
+ ); +} diff --git a/docs/src/pages/components/modal/ModalUnstyled.tsx b/docs/src/pages/components/modal/ModalUnstyled.tsx new file mode 100644 index 00000000000000..7956a3008ffa09 --- /dev/null +++ b/docs/src/pages/components/modal/ModalUnstyled.tsx @@ -0,0 +1,64 @@ +import * as React from 'react'; +import { experimentalStyled as styled } from '@material-ui/core/styles'; +import Box from '@material-ui/core/Box'; +import ModalUnstyled from '@material-ui/unstyled/ModalUnstyled'; + +const StyledModal = styled(ModalUnstyled)` + position: fixed; + z-index: 1300; + right: 0; + bottom: 0; + top: 0; + left: 0; + display: flex; + align-items: center; + justify-content: center; +`; + +const Backdrop = styled('div')` + z-index: -1; + position: fixed; + right: 0; + bottom: 0; + top: 0; + left: 0; + background-color: rgba(0, 0, 0, 0.5); + -webkit-tap-highlight-color: transparent; +`; + +const style = { + width: 400, + bgcolor: 'background.paper', + border: '2px solid #000', + p: 2, + px: 4, + pb: 3, +}; + +export default function ModalUnstyledDemo() { + const [open, setOpen] = React.useState(false); + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); + + return ( +
+ + + +

Text in a modal

+

+ Aliquid amet deserunt earum eos nihil officia porro, quasi quibusdam! +

+
+
+
+ ); +} diff --git a/docs/src/pages/components/modal/NestedModal.js b/docs/src/pages/components/modal/NestedModal.js index bca2e6c00beabd..cff94dc040589d 100644 --- a/docs/src/pages/components/modal/NestedModal.js +++ b/docs/src/pages/components/modal/NestedModal.js @@ -1,6 +1,7 @@ import * as React from 'react'; import Box from '@material-ui/core/Box'; import Modal from '@material-ui/core/Modal'; +import Button from '@material-ui/core/Button'; const style = { position: 'absolute', @@ -27,9 +28,7 @@ function ChildModal() { return ( - + Lorem ipsum, dolor sit amet consectetur adipisicing elit.

- +
@@ -62,9 +59,7 @@ export default function NestedModal() { return (
- + - + Lorem ipsum, dolor sit amet consectetur adipisicing elit.

- +
@@ -62,9 +59,7 @@ export default function NestedModal() { return (
- + ({ - root: { - height: 300, - flexGrow: 1, - minWidth: 300, - transform: 'translateZ(0)', - // The position fixed scoping doesn't work in IE11. - // Disable this demo to preserve the others. - '@media all and (-ms-high-contrast: none)': { - display: 'none', - }, - }, - modal: { - display: 'flex', - padding: theme.spacing(1), - alignItems: 'center', - justifyContent: 'center', - }, - paper: { - width: 400, - backgroundColor: theme.palette.background.paper, - border: '2px solid #000', - boxShadow: theme.shadows[5], - padding: theme.spacing(2, 4, 3), - }, -})); +import Typography from '@material-ui/core/Typography'; +import Box from '@material-ui/core/Box'; export default function ServerModal() { - const classes = useStyles(); const rootRef = React.useRef(null); return ( -
+ rootRef.current} > -
-

Server-side modal

-

+ theme.shadows[5], + p: 4, + }} + > + + Server-side modal + + If you disable JavaScript, you will still see me. -

-
+ +
-
+ ); } diff --git a/docs/src/pages/components/modal/ServerModal.tsx b/docs/src/pages/components/modal/ServerModal.tsx index 09da34fef51c5d..b2fff35ecc4c92 100644 --- a/docs/src/pages/components/modal/ServerModal.tsx +++ b/docs/src/pages/components/modal/ServerModal.tsx @@ -1,42 +1,26 @@ import * as React from 'react'; -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'; import Modal from '@material-ui/core/Modal'; - -const useStyles = makeStyles((theme: Theme) => - createStyles({ - root: { - height: 300, - flexGrow: 1, - minWidth: 300, - transform: 'translateZ(0)', - // The position fixed scoping doesn't work in IE11. - // Disable this demo to preserve the others. - '@media all and (-ms-high-contrast: none)': { - display: 'none', - }, - }, - modal: { - display: 'flex', - padding: theme.spacing(1), - alignItems: 'center', - justifyContent: 'center', - }, - paper: { - width: 400, - backgroundColor: theme.palette.background.paper, - border: '2px solid #000', - boxShadow: theme.shadows[5], - padding: theme.spacing(2, 4, 3), - }, - }), -); +import Typography from '@material-ui/core/Typography'; +import Box from '@material-ui/core/Box'; export default function ServerModal() { - const classes = useStyles(); const rootRef = React.useRef(null); return ( -
+ rootRef.current} > -
-

Server-side modal

-

+ theme.shadows[5], + p: 4, + }} + > + + Server-side modal + + If you disable JavaScript, you will still see me. -

-
+ +
-
+ ); } diff --git a/docs/src/pages/components/modal/SpringModal.js b/docs/src/pages/components/modal/SpringModal.js index b99c7502182b0d..c208dddeb58472 100644 --- a/docs/src/pages/components/modal/SpringModal.js +++ b/docs/src/pages/components/modal/SpringModal.js @@ -1,25 +1,13 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { makeStyles } from '@material-ui/core/styles'; -import Modal from '@material-ui/core/Modal'; import Backdrop from '@material-ui/core/Backdrop'; +import Box from '@material-ui/core/Box'; +import Modal from '@material-ui/core/Modal'; +import Button from '@material-ui/core/Button'; +import Typography from '@material-ui/core/Typography'; // web.cjs is required for IE11 support import { useSpring, animated } from 'react-spring/web.cjs'; -const useStyles = makeStyles((theme) => ({ - modal: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }, - paper: { - backgroundColor: theme.palette.background.paper, - border: '2px solid #000', - boxShadow: theme.shadows[5], - padding: theme.spacing(2, 4, 3), - }, -})); - const Fade = React.forwardRef(function Fade(props, ref) { const { in: open, children, onEnter, onExited, ...other } = props; const style = useSpring({ @@ -51,27 +39,29 @@ Fade.propTypes = { onExited: PropTypes.func, }; +const style = { + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: 400, + bgcolor: 'background.paper', + border: '2px solid #000', + boxShadow: 24, + p: 4, +}; + export default function SpringModal() { - const classes = useStyles(); const [open, setOpen] = React.useState(false); - - const handleOpen = () => { - setOpen(true); - }; - - const handleClose = () => { - setOpen(false); - }; + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); return (
- + -
-

Spring modal

-

react-spring animates me.

-
+ + + Text in a modal + + + Duis mollis, est non commodo luctus, nisi erat porttitor ligula. + +
diff --git a/docs/src/pages/components/modal/SpringModal.tsx b/docs/src/pages/components/modal/SpringModal.tsx index af06c61e6b5640..22734b98b27742 100644 --- a/docs/src/pages/components/modal/SpringModal.tsx +++ b/docs/src/pages/components/modal/SpringModal.tsx @@ -1,26 +1,12 @@ import * as React from 'react'; -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'; -import Modal from '@material-ui/core/Modal'; import Backdrop from '@material-ui/core/Backdrop'; +import Box from '@material-ui/core/Box'; +import Modal from '@material-ui/core/Modal'; +import Button from '@material-ui/core/Button'; +import Typography from '@material-ui/core/Typography'; // web.cjs is required for IE11 support import { useSpring, animated } from 'react-spring/web.cjs'; -const useStyles = makeStyles((theme: Theme) => - createStyles({ - modal: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }, - paper: { - backgroundColor: theme.palette.background.paper, - border: '2px solid #000', - boxShadow: theme.shadows[5], - padding: theme.spacing(2, 4, 3), - }, - }), -); - interface FadeProps { children?: React.ReactElement; in: boolean; @@ -52,27 +38,29 @@ const Fade = React.forwardRef(function Fade(props, re ); }); +const style = { + position: 'absolute' as 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: 400, + bgcolor: 'background.paper', + border: '2px solid #000', + boxShadow: 24, + p: 4, +}; + export default function SpringModal() { - const classes = useStyles(); const [open, setOpen] = React.useState(false); - - const handleOpen = () => { - setOpen(true); - }; - - const handleClose = () => { - setOpen(false); - }; + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); return (
- + -
-

Spring modal

-

react-spring animates me.

-
+ + + Text in a modal + + + Duis mollis, est non commodo luctus, nisi erat porttitor ligula. + +
diff --git a/docs/src/pages/components/modal/TransitionsModal.js b/docs/src/pages/components/modal/TransitionsModal.js index a3c9022d09482e..540eb4d7741f07 100644 --- a/docs/src/pages/components/modal/TransitionsModal.js +++ b/docs/src/pages/components/modal/TransitionsModal.js @@ -1,44 +1,34 @@ import * as React from 'react'; -import { makeStyles } from '@material-ui/core/styles'; -import Modal from '@material-ui/core/Modal'; import Backdrop from '@material-ui/core/Backdrop'; +import Box from '@material-ui/core/Box'; +import Modal from '@material-ui/core/Modal'; import Fade from '@material-ui/core/Fade'; +import Button from '@material-ui/core/Button'; +import Typography from '@material-ui/core/Typography'; -const useStyles = makeStyles((theme) => ({ - modal: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }, - paper: { - backgroundColor: theme.palette.background.paper, - border: '2px solid #000', - boxShadow: theme.shadows[5], - padding: theme.spacing(2, 4, 3), - }, -})); +const style = { + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: 400, + bgcolor: 'background.paper', + border: '2px solid #000', + boxShadow: 24, + p: 4, +}; export default function TransitionsModal() { - const classes = useStyles(); const [open, setOpen] = React.useState(false); - - const handleOpen = () => { - setOpen(true); - }; - - const handleClose = () => { - setOpen(false); - }; + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); return (
- + -
-

Transition modal

-

- react-transition-group animates me. -

-
+ + + Text in a modal + + + Duis mollis, est non commodo luctus, nisi erat porttitor ligula. + +
diff --git a/docs/src/pages/components/modal/TransitionsModal.tsx b/docs/src/pages/components/modal/TransitionsModal.tsx index c3ea011fcf76d6..e0ba787290db9e 100644 --- a/docs/src/pages/components/modal/TransitionsModal.tsx +++ b/docs/src/pages/components/modal/TransitionsModal.tsx @@ -1,46 +1,34 @@ import * as React from 'react'; -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'; -import Modal from '@material-ui/core/Modal'; import Backdrop from '@material-ui/core/Backdrop'; +import Box from '@material-ui/core/Box'; +import Modal from '@material-ui/core/Modal'; import Fade from '@material-ui/core/Fade'; +import Button from '@material-ui/core/Button'; +import Typography from '@material-ui/core/Typography'; -const useStyles = makeStyles((theme: Theme) => - createStyles({ - modal: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }, - paper: { - backgroundColor: theme.palette.background.paper, - border: '2px solid #000', - boxShadow: theme.shadows[5], - padding: theme.spacing(2, 4, 3), - }, - }), -); +const style = { + position: 'absolute' as 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: 400, + bgcolor: 'background.paper', + border: '2px solid #000', + boxShadow: 24, + p: 4, +}; export default function TransitionsModal() { - const classes = useStyles(); const [open, setOpen] = React.useState(false); - - const handleOpen = () => { - setOpen(true); - }; - - const handleClose = () => { - setOpen(false); - }; + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); return (
- + -
-

Transition modal

-

- react-transition-group animates me. -

-
+ + + Text in a modal + + + Duis mollis, est non commodo luctus, nisi erat porttitor ligula. + +
diff --git a/docs/src/pages/components/modal/modal.md b/docs/src/pages/components/modal/modal.md index 771d72cf945d39..b5468476a6f2d4 100644 --- a/docs/src/pages/components/modal/modal.md +++ b/docs/src/pages/components/modal/modal.md @@ -1,6 +1,6 @@ --- title: React Modal component -components: Modal +components: Modal, ModalUnstyled githubLabel: 'component: Modal' waiAria: https://www.w3.org/TR/wai-aria-practices/#dialog_modal --- @@ -40,6 +40,17 @@ Modal is a lower-level construct that is leveraged by the following components: Notice that you can disable the outline (often blue or gold) with the `outline: 0` CSS property. +## Unstyled modal + +The modal also comes with an unstyled version. +It's ideal for doing heavy customizations and minimizing bundle size. + +```js +import ModalUnstyled from '@material-ui/unstyled/ModalUnstyled'; +``` + +{{"demo": "pages/components/modal/ModalUnstyled.js"}} + ## Nested modal Modals can be nested, for example a select within a dialog, but stacking of more than two modals, or any two modals with a backdrop is discouraged. @@ -52,7 +63,7 @@ The open/close state of the modal can be animated with a transition component. This component should respect the following conditions: - Be a direct child descendent of the modal. -- Have an `in` prop. This corresponds to the open / close state. +- Have an `in` prop. This corresponds to the open/close state. - Call the `onEnter` callback prop when the enter transition starts. - Call the `onExited` callback prop when the exit transition is completed. These two callbacks allow the modal to unmount the child content when closed and fully transitioned. @@ -77,8 +88,8 @@ it might be a good idea to change this default behavior by enabling the `keepMou {{"demo": "pages/components/modal/KeepMountedModal.js", "defaultCodeOpen": false}} -As with any performance optimization this is not a silver bullet. Be sure to identify -bottlenecks first and then try out these optimization strategies. +As with any performance optimization, this is not a silver bullet. +Be sure to identify bottlenecks first, and then try out these optimization strategies. ## Server-side modal @@ -93,7 +104,7 @@ In order to display the modal, you need to disable the portal feature with the ` The modal moves the focus back to the body of the component if the focus tries to escape it. -This is done for accessibility purposes, however, it might create issues. +This is done for accessibility purposes. However, it might create issues. In the event the users need to interact with another part of the page, e.g. with a chatbot window, you can disable the behavior: ```jsx diff --git a/docs/src/pages/components/slider/slider.md b/docs/src/pages/components/slider/slider.md index 752ae55f66e569..867572642680da 100644 --- a/docs/src/pages/components/slider/slider.md +++ b/docs/src/pages/components/slider/slider.md @@ -114,6 +114,13 @@ Increasing _x_ by one increases the represented value by factor _2_. ## Unstyled slider +The slider also comes with an unstyled version. +It's ideal for doing heavy customizations and minimizing bundle size. + +```js +import SliderUnstyled from '@material-ui/unstyled/SliderUnstyled'; +``` + {{"demo": "pages/components/slider/UnstyledSlider.js"}} ## Accessibility diff --git a/docs/src/pages/components/speed-dial/ControlledOpenSpeedDial.js b/docs/src/pages/components/speed-dial/ControlledOpenSpeedDial.js index 1aa4267f963531..5d7f2401c3f744 100644 --- a/docs/src/pages/components/speed-dial/ControlledOpenSpeedDial.js +++ b/docs/src/pages/components/speed-dial/ControlledOpenSpeedDial.js @@ -31,14 +31,8 @@ const actions = [ export default function ControlledOpenSpeedDial() { const classes = useStyles(); const [open, setOpen] = React.useState(false); - - const handleOpen = () => { - setOpen(true); - }; - - const handleClose = () => { - setOpen(false); - }; + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); return (
diff --git a/docs/src/pages/components/speed-dial/ControlledOpenSpeedDial.tsx b/docs/src/pages/components/speed-dial/ControlledOpenSpeedDial.tsx index 65cb1f216073be..96d984044a965c 100644 --- a/docs/src/pages/components/speed-dial/ControlledOpenSpeedDial.tsx +++ b/docs/src/pages/components/speed-dial/ControlledOpenSpeedDial.tsx @@ -31,14 +31,8 @@ const actions = [ export default function ControlledOpenSpeedDial() { const classes = useStyles(); const [open, setOpen] = React.useState(false); - - const handleOpen = () => { - setOpen(true); - }; - - const handleClose = () => { - setOpen(false); - }; + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); return (
diff --git a/docs/src/pages/components/speed-dial/SpeedDialTooltipOpen.js b/docs/src/pages/components/speed-dial/SpeedDialTooltipOpen.js index 9e3d675511e1b4..6f2c611e6d333a 100644 --- a/docs/src/pages/components/speed-dial/SpeedDialTooltipOpen.js +++ b/docs/src/pages/components/speed-dial/SpeedDialTooltipOpen.js @@ -32,14 +32,8 @@ const actions = [ export default function SpeedDialTooltipOpen() { const classes = useStyles(); const [open, setOpen] = React.useState(false); - - const handleOpen = () => { - setOpen(true); - }; - - const handleClose = () => { - setOpen(false); - }; + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); return (
diff --git a/docs/src/pages/components/speed-dial/SpeedDialTooltipOpen.tsx b/docs/src/pages/components/speed-dial/SpeedDialTooltipOpen.tsx index c96f81cc3a5761..728d311417f545 100644 --- a/docs/src/pages/components/speed-dial/SpeedDialTooltipOpen.tsx +++ b/docs/src/pages/components/speed-dial/SpeedDialTooltipOpen.tsx @@ -34,14 +34,8 @@ const actions = [ export default function SpeedDialTooltipOpen() { const classes = useStyles(); const [open, setOpen] = React.useState(false); - - const handleOpen = () => { - setOpen(true); - }; - - const handleClose = () => { - setOpen(false); - }; + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); return (
diff --git a/docs/src/pagesApi.js b/docs/src/pagesApi.js index 29acd28472bd97..2dd248017b207a 100644 --- a/docs/src/pagesApi.js +++ b/docs/src/pagesApi.js @@ -79,6 +79,7 @@ module.exports = [ { pathname: '/api-docs/mobile-stepper' }, { pathname: '/api-docs/mobile-time-picker' }, { pathname: '/api-docs/modal' }, + { pathname: '/api-docs/modal-unstyled' }, { pathname: '/api-docs/native-select' }, { pathname: '/api-docs/no-ssr' }, { pathname: '/api-docs/outlined-input' }, diff --git a/docs/translations/api-docs/modal-unstyled/modal-unstyled-de.json b/docs/translations/api-docs/modal-unstyled/modal-unstyled-de.json new file mode 100644 index 00000000000000..f7a5160fc0258b --- /dev/null +++ b/docs/translations/api-docs/modal-unstyled/modal-unstyled-de.json @@ -0,0 +1,33 @@ +{ + "componentDescription": "Modal is a lower-level construct that is leveraged by the following components:\n\n- [Dialog](/api/dialog/)\n- [Drawer](/api/drawer/)\n- [Menu](/api/menu/)\n- [Popover](/api/popover/)\n\nIf you are creating a modal dialog, you probably want to use the [Dialog](/api/dialog/) component\nrather than directly using Modal.\n\nThis component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals).", + "propDescriptions": { + "BackdropComponent": "A backdrop component. This prop enables custom backdrop rendering.", + "BackdropProps": "Props applied to the Backdrop element.", + "children": "A single child content element.
⚠️ Needs to be able to hold a ref.", + "classes": "Override or extend the styles applied to the component. See CSS API below for more details.", + "closeAfterTransition": "When set to true the Modal waits until a nested Transition is completed before closing.", + "component": "The component used for the root node. Either a string to use a HTML element or a component.", + "components": "The components used for each slot inside the Modal. Either a string to use a HTML element or a component.", + "componentsProps": "The props used for each slot inside the Modal.", + "container": "An HTML element or function that returns one. The container will have the portal children appended to it.
By default, it uses the body of the top-level document object, so it's simply document.body most of the time.", + "disableAutoFocus": "If true, the modal will not automatically shift focus to itself when it opens, and replace it to the last focused element when it closes. This also works correctly with any modal children that have the disableAutoFocus prop.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEnforceFocus": "If true, the modal will not prevent focus from leaving the modal while open.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEscapeKeyDown": "If true, hitting escape will not fire the onClose callback.", + "disablePortal": "The children will be under the DOM hierarchy of the parent component.", + "disableRestoreFocus": "If true, the modal will not restore focus to previously focused element once modal is hidden.", + "disableScrollLock": "Disable the scroll lock behavior.", + "hideBackdrop": "If true, the backdrop is not rendered.", + "keepMounted": "Always keep the children in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Modal.", + "onBackdropClick": "Callback fired when the backdrop is clicked.", + "onClose": "Callback fired when the component requests to be closed. The reason parameter can optionally be used to control the response to onClose.

Signature:
function(event: object, reason: string) => void
event: The event source of the callback.
reason: Can be: "escapeKeyDown", "backdropClick".", + "open": "If true, the component is shown." + }, + "classDescriptions": { + "root": { "description": "Styles applied to the root element." }, + "hidden": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "the Modal has exited" + } + } +} diff --git a/docs/translations/api-docs/modal-unstyled/modal-unstyled-es.json b/docs/translations/api-docs/modal-unstyled/modal-unstyled-es.json new file mode 100644 index 00000000000000..f7a5160fc0258b --- /dev/null +++ b/docs/translations/api-docs/modal-unstyled/modal-unstyled-es.json @@ -0,0 +1,33 @@ +{ + "componentDescription": "Modal is a lower-level construct that is leveraged by the following components:\n\n- [Dialog](/api/dialog/)\n- [Drawer](/api/drawer/)\n- [Menu](/api/menu/)\n- [Popover](/api/popover/)\n\nIf you are creating a modal dialog, you probably want to use the [Dialog](/api/dialog/) component\nrather than directly using Modal.\n\nThis component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals).", + "propDescriptions": { + "BackdropComponent": "A backdrop component. This prop enables custom backdrop rendering.", + "BackdropProps": "Props applied to the Backdrop element.", + "children": "A single child content element.
⚠️ Needs to be able to hold a ref.", + "classes": "Override or extend the styles applied to the component. See CSS API below for more details.", + "closeAfterTransition": "When set to true the Modal waits until a nested Transition is completed before closing.", + "component": "The component used for the root node. Either a string to use a HTML element or a component.", + "components": "The components used for each slot inside the Modal. Either a string to use a HTML element or a component.", + "componentsProps": "The props used for each slot inside the Modal.", + "container": "An HTML element or function that returns one. The container will have the portal children appended to it.
By default, it uses the body of the top-level document object, so it's simply document.body most of the time.", + "disableAutoFocus": "If true, the modal will not automatically shift focus to itself when it opens, and replace it to the last focused element when it closes. This also works correctly with any modal children that have the disableAutoFocus prop.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEnforceFocus": "If true, the modal will not prevent focus from leaving the modal while open.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEscapeKeyDown": "If true, hitting escape will not fire the onClose callback.", + "disablePortal": "The children will be under the DOM hierarchy of the parent component.", + "disableRestoreFocus": "If true, the modal will not restore focus to previously focused element once modal is hidden.", + "disableScrollLock": "Disable the scroll lock behavior.", + "hideBackdrop": "If true, the backdrop is not rendered.", + "keepMounted": "Always keep the children in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Modal.", + "onBackdropClick": "Callback fired when the backdrop is clicked.", + "onClose": "Callback fired when the component requests to be closed. The reason parameter can optionally be used to control the response to onClose.

Signature:
function(event: object, reason: string) => void
event: The event source of the callback.
reason: Can be: "escapeKeyDown", "backdropClick".", + "open": "If true, the component is shown." + }, + "classDescriptions": { + "root": { "description": "Styles applied to the root element." }, + "hidden": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "the Modal has exited" + } + } +} diff --git a/docs/translations/api-docs/modal-unstyled/modal-unstyled-fr.json b/docs/translations/api-docs/modal-unstyled/modal-unstyled-fr.json new file mode 100644 index 00000000000000..f7a5160fc0258b --- /dev/null +++ b/docs/translations/api-docs/modal-unstyled/modal-unstyled-fr.json @@ -0,0 +1,33 @@ +{ + "componentDescription": "Modal is a lower-level construct that is leveraged by the following components:\n\n- [Dialog](/api/dialog/)\n- [Drawer](/api/drawer/)\n- [Menu](/api/menu/)\n- [Popover](/api/popover/)\n\nIf you are creating a modal dialog, you probably want to use the [Dialog](/api/dialog/) component\nrather than directly using Modal.\n\nThis component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals).", + "propDescriptions": { + "BackdropComponent": "A backdrop component. This prop enables custom backdrop rendering.", + "BackdropProps": "Props applied to the Backdrop element.", + "children": "A single child content element.
⚠️ Needs to be able to hold a ref.", + "classes": "Override or extend the styles applied to the component. See CSS API below for more details.", + "closeAfterTransition": "When set to true the Modal waits until a nested Transition is completed before closing.", + "component": "The component used for the root node. Either a string to use a HTML element or a component.", + "components": "The components used for each slot inside the Modal. Either a string to use a HTML element or a component.", + "componentsProps": "The props used for each slot inside the Modal.", + "container": "An HTML element or function that returns one. The container will have the portal children appended to it.
By default, it uses the body of the top-level document object, so it's simply document.body most of the time.", + "disableAutoFocus": "If true, the modal will not automatically shift focus to itself when it opens, and replace it to the last focused element when it closes. This also works correctly with any modal children that have the disableAutoFocus prop.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEnforceFocus": "If true, the modal will not prevent focus from leaving the modal while open.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEscapeKeyDown": "If true, hitting escape will not fire the onClose callback.", + "disablePortal": "The children will be under the DOM hierarchy of the parent component.", + "disableRestoreFocus": "If true, the modal will not restore focus to previously focused element once modal is hidden.", + "disableScrollLock": "Disable the scroll lock behavior.", + "hideBackdrop": "If true, the backdrop is not rendered.", + "keepMounted": "Always keep the children in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Modal.", + "onBackdropClick": "Callback fired when the backdrop is clicked.", + "onClose": "Callback fired when the component requests to be closed. The reason parameter can optionally be used to control the response to onClose.

Signature:
function(event: object, reason: string) => void
event: The event source of the callback.
reason: Can be: "escapeKeyDown", "backdropClick".", + "open": "If true, the component is shown." + }, + "classDescriptions": { + "root": { "description": "Styles applied to the root element." }, + "hidden": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "the Modal has exited" + } + } +} diff --git a/docs/translations/api-docs/modal-unstyled/modal-unstyled-ja.json b/docs/translations/api-docs/modal-unstyled/modal-unstyled-ja.json new file mode 100644 index 00000000000000..f7a5160fc0258b --- /dev/null +++ b/docs/translations/api-docs/modal-unstyled/modal-unstyled-ja.json @@ -0,0 +1,33 @@ +{ + "componentDescription": "Modal is a lower-level construct that is leveraged by the following components:\n\n- [Dialog](/api/dialog/)\n- [Drawer](/api/drawer/)\n- [Menu](/api/menu/)\n- [Popover](/api/popover/)\n\nIf you are creating a modal dialog, you probably want to use the [Dialog](/api/dialog/) component\nrather than directly using Modal.\n\nThis component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals).", + "propDescriptions": { + "BackdropComponent": "A backdrop component. This prop enables custom backdrop rendering.", + "BackdropProps": "Props applied to the Backdrop element.", + "children": "A single child content element.
⚠️ Needs to be able to hold a ref.", + "classes": "Override or extend the styles applied to the component. See CSS API below for more details.", + "closeAfterTransition": "When set to true the Modal waits until a nested Transition is completed before closing.", + "component": "The component used for the root node. Either a string to use a HTML element or a component.", + "components": "The components used for each slot inside the Modal. Either a string to use a HTML element or a component.", + "componentsProps": "The props used for each slot inside the Modal.", + "container": "An HTML element or function that returns one. The container will have the portal children appended to it.
By default, it uses the body of the top-level document object, so it's simply document.body most of the time.", + "disableAutoFocus": "If true, the modal will not automatically shift focus to itself when it opens, and replace it to the last focused element when it closes. This also works correctly with any modal children that have the disableAutoFocus prop.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEnforceFocus": "If true, the modal will not prevent focus from leaving the modal while open.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEscapeKeyDown": "If true, hitting escape will not fire the onClose callback.", + "disablePortal": "The children will be under the DOM hierarchy of the parent component.", + "disableRestoreFocus": "If true, the modal will not restore focus to previously focused element once modal is hidden.", + "disableScrollLock": "Disable the scroll lock behavior.", + "hideBackdrop": "If true, the backdrop is not rendered.", + "keepMounted": "Always keep the children in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Modal.", + "onBackdropClick": "Callback fired when the backdrop is clicked.", + "onClose": "Callback fired when the component requests to be closed. The reason parameter can optionally be used to control the response to onClose.

Signature:
function(event: object, reason: string) => void
event: The event source of the callback.
reason: Can be: "escapeKeyDown", "backdropClick".", + "open": "If true, the component is shown." + }, + "classDescriptions": { + "root": { "description": "Styles applied to the root element." }, + "hidden": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "the Modal has exited" + } + } +} diff --git a/docs/translations/api-docs/modal-unstyled/modal-unstyled-pt.json b/docs/translations/api-docs/modal-unstyled/modal-unstyled-pt.json new file mode 100644 index 00000000000000..f7a5160fc0258b --- /dev/null +++ b/docs/translations/api-docs/modal-unstyled/modal-unstyled-pt.json @@ -0,0 +1,33 @@ +{ + "componentDescription": "Modal is a lower-level construct that is leveraged by the following components:\n\n- [Dialog](/api/dialog/)\n- [Drawer](/api/drawer/)\n- [Menu](/api/menu/)\n- [Popover](/api/popover/)\n\nIf you are creating a modal dialog, you probably want to use the [Dialog](/api/dialog/) component\nrather than directly using Modal.\n\nThis component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals).", + "propDescriptions": { + "BackdropComponent": "A backdrop component. This prop enables custom backdrop rendering.", + "BackdropProps": "Props applied to the Backdrop element.", + "children": "A single child content element.
⚠️ Needs to be able to hold a ref.", + "classes": "Override or extend the styles applied to the component. See CSS API below for more details.", + "closeAfterTransition": "When set to true the Modal waits until a nested Transition is completed before closing.", + "component": "The component used for the root node. Either a string to use a HTML element or a component.", + "components": "The components used for each slot inside the Modal. Either a string to use a HTML element or a component.", + "componentsProps": "The props used for each slot inside the Modal.", + "container": "An HTML element or function that returns one. The container will have the portal children appended to it.
By default, it uses the body of the top-level document object, so it's simply document.body most of the time.", + "disableAutoFocus": "If true, the modal will not automatically shift focus to itself when it opens, and replace it to the last focused element when it closes. This also works correctly with any modal children that have the disableAutoFocus prop.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEnforceFocus": "If true, the modal will not prevent focus from leaving the modal while open.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEscapeKeyDown": "If true, hitting escape will not fire the onClose callback.", + "disablePortal": "The children will be under the DOM hierarchy of the parent component.", + "disableRestoreFocus": "If true, the modal will not restore focus to previously focused element once modal is hidden.", + "disableScrollLock": "Disable the scroll lock behavior.", + "hideBackdrop": "If true, the backdrop is not rendered.", + "keepMounted": "Always keep the children in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Modal.", + "onBackdropClick": "Callback fired when the backdrop is clicked.", + "onClose": "Callback fired when the component requests to be closed. The reason parameter can optionally be used to control the response to onClose.

Signature:
function(event: object, reason: string) => void
event: The event source of the callback.
reason: Can be: "escapeKeyDown", "backdropClick".", + "open": "If true, the component is shown." + }, + "classDescriptions": { + "root": { "description": "Styles applied to the root element." }, + "hidden": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "the Modal has exited" + } + } +} diff --git a/docs/translations/api-docs/modal-unstyled/modal-unstyled-ru.json b/docs/translations/api-docs/modal-unstyled/modal-unstyled-ru.json new file mode 100644 index 00000000000000..f7a5160fc0258b --- /dev/null +++ b/docs/translations/api-docs/modal-unstyled/modal-unstyled-ru.json @@ -0,0 +1,33 @@ +{ + "componentDescription": "Modal is a lower-level construct that is leveraged by the following components:\n\n- [Dialog](/api/dialog/)\n- [Drawer](/api/drawer/)\n- [Menu](/api/menu/)\n- [Popover](/api/popover/)\n\nIf you are creating a modal dialog, you probably want to use the [Dialog](/api/dialog/) component\nrather than directly using Modal.\n\nThis component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals).", + "propDescriptions": { + "BackdropComponent": "A backdrop component. This prop enables custom backdrop rendering.", + "BackdropProps": "Props applied to the Backdrop element.", + "children": "A single child content element.
⚠️ Needs to be able to hold a ref.", + "classes": "Override or extend the styles applied to the component. See CSS API below for more details.", + "closeAfterTransition": "When set to true the Modal waits until a nested Transition is completed before closing.", + "component": "The component used for the root node. Either a string to use a HTML element or a component.", + "components": "The components used for each slot inside the Modal. Either a string to use a HTML element or a component.", + "componentsProps": "The props used for each slot inside the Modal.", + "container": "An HTML element or function that returns one. The container will have the portal children appended to it.
By default, it uses the body of the top-level document object, so it's simply document.body most of the time.", + "disableAutoFocus": "If true, the modal will not automatically shift focus to itself when it opens, and replace it to the last focused element when it closes. This also works correctly with any modal children that have the disableAutoFocus prop.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEnforceFocus": "If true, the modal will not prevent focus from leaving the modal while open.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEscapeKeyDown": "If true, hitting escape will not fire the onClose callback.", + "disablePortal": "The children will be under the DOM hierarchy of the parent component.", + "disableRestoreFocus": "If true, the modal will not restore focus to previously focused element once modal is hidden.", + "disableScrollLock": "Disable the scroll lock behavior.", + "hideBackdrop": "If true, the backdrop is not rendered.", + "keepMounted": "Always keep the children in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Modal.", + "onBackdropClick": "Callback fired when the backdrop is clicked.", + "onClose": "Callback fired when the component requests to be closed. The reason parameter can optionally be used to control the response to onClose.

Signature:
function(event: object, reason: string) => void
event: The event source of the callback.
reason: Can be: "escapeKeyDown", "backdropClick".", + "open": "If true, the component is shown." + }, + "classDescriptions": { + "root": { "description": "Styles applied to the root element." }, + "hidden": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "the Modal has exited" + } + } +} diff --git a/docs/translations/api-docs/modal-unstyled/modal-unstyled-zh.json b/docs/translations/api-docs/modal-unstyled/modal-unstyled-zh.json new file mode 100644 index 00000000000000..f7a5160fc0258b --- /dev/null +++ b/docs/translations/api-docs/modal-unstyled/modal-unstyled-zh.json @@ -0,0 +1,33 @@ +{ + "componentDescription": "Modal is a lower-level construct that is leveraged by the following components:\n\n- [Dialog](/api/dialog/)\n- [Drawer](/api/drawer/)\n- [Menu](/api/menu/)\n- [Popover](/api/popover/)\n\nIf you are creating a modal dialog, you probably want to use the [Dialog](/api/dialog/) component\nrather than directly using Modal.\n\nThis component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals).", + "propDescriptions": { + "BackdropComponent": "A backdrop component. This prop enables custom backdrop rendering.", + "BackdropProps": "Props applied to the Backdrop element.", + "children": "A single child content element.
⚠️ Needs to be able to hold a ref.", + "classes": "Override or extend the styles applied to the component. See CSS API below for more details.", + "closeAfterTransition": "When set to true the Modal waits until a nested Transition is completed before closing.", + "component": "The component used for the root node. Either a string to use a HTML element or a component.", + "components": "The components used for each slot inside the Modal. Either a string to use a HTML element or a component.", + "componentsProps": "The props used for each slot inside the Modal.", + "container": "An HTML element or function that returns one. The container will have the portal children appended to it.
By default, it uses the body of the top-level document object, so it's simply document.body most of the time.", + "disableAutoFocus": "If true, the modal will not automatically shift focus to itself when it opens, and replace it to the last focused element when it closes. This also works correctly with any modal children that have the disableAutoFocus prop.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEnforceFocus": "If true, the modal will not prevent focus from leaving the modal while open.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEscapeKeyDown": "If true, hitting escape will not fire the onClose callback.", + "disablePortal": "The children will be under the DOM hierarchy of the parent component.", + "disableRestoreFocus": "If true, the modal will not restore focus to previously focused element once modal is hidden.", + "disableScrollLock": "Disable the scroll lock behavior.", + "hideBackdrop": "If true, the backdrop is not rendered.", + "keepMounted": "Always keep the children in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Modal.", + "onBackdropClick": "Callback fired when the backdrop is clicked.", + "onClose": "Callback fired when the component requests to be closed. The reason parameter can optionally be used to control the response to onClose.

Signature:
function(event: object, reason: string) => void
event: The event source of the callback.
reason: Can be: "escapeKeyDown", "backdropClick".", + "open": "If true, the component is shown." + }, + "classDescriptions": { + "root": { "description": "Styles applied to the root element." }, + "hidden": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "the Modal has exited" + } + } +} diff --git a/docs/translations/api-docs/modal-unstyled/modal-unstyled.json b/docs/translations/api-docs/modal-unstyled/modal-unstyled.json new file mode 100644 index 00000000000000..9c21169bea4ae2 --- /dev/null +++ b/docs/translations/api-docs/modal-unstyled/modal-unstyled.json @@ -0,0 +1,33 @@ +{ + "componentDescription": "Modal is a lower-level construct that is leveraged by the following components:\n\n- [Dialog](/api/dialog/)\n- [Drawer](/api/drawer/)\n- [Menu](/api/menu/)\n- [Popover](/api/popover/)\n\nIf you are creating a modal dialog, you probably want to use the [Dialog](/api/dialog/) component\nrather than directly using Modal.\n\nThis component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals).", + "propDescriptions": { + "BackdropComponent": "A backdrop component. This prop enables custom backdrop rendering.", + "BackdropProps": "Props applied to the BackdropUnstyled element.", + "children": "A single child content element.
⚠️ Needs to be able to hold a ref.", + "classes": "Override or extend the styles applied to the component. See CSS API below for more details.", + "closeAfterTransition": "When set to true the Modal waits until a nested Transition is completed before closing.", + "component": "The component used for the root node. Either a string to use a HTML element or a component.", + "components": "The components used for each slot inside the Modal. Either a string to use a HTML element or a component.", + "componentsProps": "The props used for each slot inside the Modal.", + "container": "An HTML element or function that returns one. The container will have the portal children appended to it.
By default, it uses the body of the top-level document object, so it's simply document.body most of the time.", + "disableAutoFocus": "If true, the modal will not automatically shift focus to itself when it opens, and replace it to the last focused element when it closes. This also works correctly with any modal children that have the disableAutoFocus prop.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEnforceFocus": "If true, the modal will not prevent focus from leaving the modal while open.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", + "disableEscapeKeyDown": "If true, hitting escape will not fire the onClose callback.", + "disablePortal": "The children will be under the DOM hierarchy of the parent component.", + "disableRestoreFocus": "If true, the modal will not restore focus to previously focused element once modal is hidden.", + "disableScrollLock": "Disable the scroll lock behavior.", + "hideBackdrop": "If true, the backdrop is not rendered.", + "keepMounted": "Always keep the children in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Modal.", + "onBackdropClick": "Callback fired when the backdrop is clicked.", + "onClose": "Callback fired when the component requests to be closed. The reason parameter can optionally be used to control the response to onClose.

Signature:
function(event: object, reason: string) => void
event: The event source of the callback.
reason: Can be: "escapeKeyDown", "backdropClick".", + "open": "If true, the component is shown." + }, + "classDescriptions": { + "root": { "description": "Styles applied to the root element." }, + "hidden": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "the Modal has exited" + } + } +} diff --git a/docs/translations/api-docs/modal/modal.json b/docs/translations/api-docs/modal/modal.json index 4f124cd7f68515..4530f11dc4cbbe 100644 --- a/docs/translations/api-docs/modal/modal.json +++ b/docs/translations/api-docs/modal/modal.json @@ -4,7 +4,10 @@ "BackdropComponent": "A backdrop component. This prop enables custom backdrop rendering.", "BackdropProps": "Props applied to the Backdrop element.", "children": "A single child content element.
⚠️ Needs to be able to hold a ref.", + "classes": "Override or extend the styles applied to the component. See CSS API below for more details.", "closeAfterTransition": "When set to true the Modal waits until a nested Transition is completed before closing.", + "components": "The components used for each slot inside the Modal. Either a string to use a HTML element or a component.", + "componentsProps": "The props used for each slot inside the Modal.", "container": "An HTML element or function that returns one. The container will have the portal children appended to it.
By default, it uses the body of the top-level document object, so it's simply document.body most of the time.", "disableAutoFocus": "If true, the modal will not automatically shift focus to itself when it opens, and replace it to the last focused element when it closes. This also works correctly with any modal children that have the disableAutoFocus prop.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", "disableEnforceFocus": "If true, the modal will not prevent focus from leaving the modal while open.
Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", @@ -16,7 +19,16 @@ "keepMounted": "Always keep the children in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Modal.", "onBackdropClick": "Callback fired when the backdrop is clicked.", "onClose": "Callback fired when the component requests to be closed. The reason parameter can optionally be used to control the response to onClose.

Signature:
function(event: object, reason: string) => void
event: The event source of the callback.
reason: Can be: "escapeKeyDown", "backdropClick".", - "open": "If true, the component is shown." + "open": "If true, the component is shown.", + "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.", + "component": "The component used for the root node. Either a string to use a HTML element or a component." }, - "classDescriptions": {} + "classDescriptions": { + "root": { "description": "Styles applied to the root element." }, + "hidden": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "the Modal has exited" + } + } } diff --git a/packages/material-ui-unstyled/src/BackdropUnstyled/BackdropUnstyled.d.ts b/packages/material-ui-unstyled/src/BackdropUnstyled/BackdropUnstyled.d.ts index 20ea84c715e493..0896602cd20102 100644 --- a/packages/material-ui-unstyled/src/BackdropUnstyled/BackdropUnstyled.d.ts +++ b/packages/material-ui-unstyled/src/BackdropUnstyled/BackdropUnstyled.d.ts @@ -27,7 +27,6 @@ export interface BackdropUnstyledTypeMap

- {children} - + /> ); }); @@ -68,7 +66,6 @@ BackdropUnstyled.propTypes = { children: PropTypes.node, /** * Override or extend the styles applied to the component. - * @default {} */ classes: PropTypes.object, /** diff --git a/packages/material-ui-unstyled/src/BadgeUnstyled/BadgeUnstyled.d.ts b/packages/material-ui-unstyled/src/BadgeUnstyled/BadgeUnstyled.d.ts index 6d40cd10278ef6..e43160cabceafb 100644 --- a/packages/material-ui-unstyled/src/BadgeUnstyled/BadgeUnstyled.d.ts +++ b/packages/material-ui-unstyled/src/BadgeUnstyled/BadgeUnstyled.d.ts @@ -54,7 +54,6 @@ export interface BadgeUnstyledTypeMap

max ? `${max}+` : badgeContent; } - const classes = useUtilityClasses({ ...styleProps, classes: classesProp }); + const classes = useUtilityClasses(styleProps); const Root = components.Root || component; const rootProps = componentsProps.root || {}; @@ -149,7 +150,6 @@ BadgeUnstyled.propTypes = { children: PropTypes.node, /** * Override or extend the styles applied to the component. - * @default {} */ classes: PropTypes.object, /** diff --git a/packages/material-ui/src/Modal/ModalManager.test.js b/packages/material-ui-unstyled/src/ModalUnstyled/ModalManager.test.js similarity index 99% rename from packages/material-ui/src/Modal/ModalManager.test.js rename to packages/material-ui-unstyled/src/ModalUnstyled/ModalManager.test.js index 3d523cad4a13e0..8591bea78170db 100644 --- a/packages/material-ui/src/Modal/ModalManager.test.js +++ b/packages/material-ui-unstyled/src/ModalUnstyled/ModalManager.test.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import getScrollbarSize from '../utils/getScrollbarSize'; +import { unstable_getScrollbarSize as getScrollbarSize } from '@material-ui/utils'; import ModalManager from './ModalManager'; describe('ModalManager', () => { diff --git a/packages/material-ui/src/Modal/ModalManager.ts b/packages/material-ui-unstyled/src/ModalUnstyled/ModalManager.ts similarity index 97% rename from packages/material-ui/src/Modal/ModalManager.ts rename to packages/material-ui-unstyled/src/ModalUnstyled/ModalManager.ts index 294a015b542584..69317c0b4496c0 100644 --- a/packages/material-ui/src/Modal/ModalManager.ts +++ b/packages/material-ui-unstyled/src/ModalUnstyled/ModalManager.ts @@ -1,6 +1,8 @@ -import getScrollbarSize from '../utils/getScrollbarSize'; -import ownerDocument from '../utils/ownerDocument'; -import ownerWindow from '../utils/ownerWindow'; +import { + unstable_ownerWindow as ownerWindow, + unstable_ownerDocument as ownerDocument, + unstable_getScrollbarSize as getScrollbarSize, +} from '@material-ui/utils'; export interface ManagedModalProps { disableScrollLock?: boolean; diff --git a/packages/material-ui-unstyled/src/ModalUnstyled/ModalUnstyled.d.ts b/packages/material-ui-unstyled/src/ModalUnstyled/ModalUnstyled.d.ts new file mode 100644 index 00000000000000..97553729948ac1 --- /dev/null +++ b/packages/material-ui-unstyled/src/ModalUnstyled/ModalUnstyled.d.ts @@ -0,0 +1,175 @@ +import * as React from 'react'; +import { BackdropUnstyledProps } from '../BackdropUnstyled'; +import { PortalProps } from '../Portal'; +import { OverridableComponent, OverridableTypeMap, OverrideProps } from '../OverridableComponent'; + +export interface ModalUnstyledTypeMap

{ + props: P & { + /** + * A backdrop component. This prop enables custom backdrop rendering. + */ + BackdropComponent?: React.ElementType; + /** + * Props applied to the [`BackdropUnstyled`](/api/backdrop-unstyled/) element. + */ + BackdropProps?: Partial; + /** + * A single child content element. + */ + children: React.ReactElement; + /** + * Override or extend the styles applied to the component. + */ + classes?: { + /** Styles applied to the root element. */ + root?: string; + /** Styles applied to the root element if the `Modal` has exited. */ + hidden?: string; + }; + /** + * When set to true the Modal waits until a nested Transition is completed before closing. + * @default false + */ + closeAfterTransition?: boolean; + /** + * The components used for each slot inside the Modal. + * Either a string to use a HTML element or a component. + * @default {} + */ + components?: { + Root?: React.ElementType; + }; + /** + * The props used for each slot inside the Modal. + * @default {} + */ + componentsProps?: { + root?: { + as: React.ElementType; + styleProps?: Omit['props'], 'components' | 'componentsProps'>; + }; + }; + /** + * An HTML element or function that returns one. + * The `container` will have the portal children appended to it. + * + * By default, it uses the body of the top-level document object, + * so it's simply `document.body` most of the time. + */ + container?: PortalProps['container']; + /** + * If `true`, the modal will not automatically shift focus to itself when it opens, and + * replace it to the last focused element when it closes. + * This also works correctly with any modal children that have the `disableAutoFocus` prop. + * + * Generally this should never be set to `true` as it makes the modal less + * accessible to assistive technologies, like screen readers. + * @default false + */ + disableAutoFocus?: boolean; + /** + * If `true`, the modal will not prevent focus from leaving the modal while open. + * + * Generally this should never be set to `true` as it makes the modal less + * accessible to assistive technologies, like screen readers. + * @default false + */ + disableEnforceFocus?: boolean; + /** + * If `true`, hitting escape will not fire the `onClose` callback. + * @default false + */ + disableEscapeKeyDown?: boolean; + /** + * The `children` will be under the DOM hierarchy of the parent component. + * @default false + */ + disablePortal?: PortalProps['disablePortal']; + /** + * If `true`, the modal will not restore focus to previously focused element once + * modal is hidden. + * @default false + */ + disableRestoreFocus?: boolean; + /** + * Disable the scroll lock behavior. + * @default false + */ + disableScrollLock?: boolean; + /** + * If `true`, the backdrop is not rendered. + * @default false + */ + hideBackdrop?: boolean; + /** + * Always keep the children in the DOM. + * This prop can be useful in SEO situation or + * when you want to maximize the responsiveness of the Modal. + * @default false + */ + keepMounted?: boolean; + /** + * Callback fired when the backdrop is clicked. + */ + onBackdropClick?: React.ReactEventHandler<{}>; + /** + * Callback fired when the component requests to be closed. + * The `reason` parameter can optionally be used to control the response to `onClose`. + * + * @param {object} event The event source of the callback. + * @param {string} reason Can be: `"escapeKeyDown"`, `"backdropClick"`. + */ + onClose?: { + bivarianceHack(event: {}, reason: 'backdropClick' | 'escapeKeyDown'): void; + }['bivarianceHack']; + /** + * If `true`, the component is shown. + */ + open: boolean; + }; + defaultComponent: D; +} + +/** + * Utility to create component types that inherit props from ModalUnstyled. + */ +export interface ExtendModalUnstyledTypeMap { + props: M['props'] & ModalUnstyledTypeMap['props']; + defaultComponent: M['defaultComponent']; +} + +export type ExtendModalUnstyled = OverridableComponent< + ExtendModalUnstyledTypeMap +>; + +export type ModalUnstyledClassKey = keyof NonNullable; + +/** + * Modal is a lower-level construct that is leveraged by the following components: + * + * * [Dialog](https://material-ui.com/api/dialog/) + * * [Drawer](https://material-ui.com/api/drawer/) + * * [Menu](https://material-ui.com/api/menu/) + * * [Popover](https://material-ui.com/api/popover/) + * + * If you are creating a modal dialog, you probably want to use the [Dialog](https://material-ui.com/api/dialog/) component + * rather than directly using Modal. + * + * This component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals). + * + * Demos: + * + * - [Modal](https://material-ui.com/components/modal/) + * + * API: + * + * - [ModalUnstyled API](https://material-ui.com/api/modal-unstyled/) + */ +declare const ModalUnstyled: OverridableComponent; + +export type ModalUnstyledProps< + D extends React.ElementType = ModalUnstyledTypeMap['defaultComponent'], + P = {} +> = OverrideProps, D>; + +export default ModalUnstyled; diff --git a/packages/material-ui-unstyled/src/ModalUnstyled/ModalUnstyled.js b/packages/material-ui-unstyled/src/ModalUnstyled/ModalUnstyled.js new file mode 100644 index 00000000000000..561734224729b0 --- /dev/null +++ b/packages/material-ui-unstyled/src/ModalUnstyled/ModalUnstyled.js @@ -0,0 +1,419 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import clsx from 'clsx'; +import { + elementAcceptingRef, + HTMLElementType, + unstable_ownerDocument as ownerDocument, + unstable_useForkRef as useForkRef, + unstable_createChainedFunction as createChainedFunction, + unstable_useEventCallback as useEventCallback, +} from '@material-ui/utils'; +import composeClasses from '../composeClasses'; +import isHostComponent from '../utils/isHostComponent'; +import Portal from '../Portal'; +import ModalManager, { ariaHidden } from './ModalManager'; +import TrapFocus from '../Unstable_TrapFocus'; +import { getModalUtilityClass } from './modalUnstyledClasses'; + +const useUtilityClasses = (styleProps) => { + const { open, exited, classes } = styleProps; + + const slots = { + root: ['root', !open && exited && 'hidden'], + }; + + return composeClasses(slots, getModalUtilityClass, classes); +}; + +function getContainer(container) { + return typeof container === 'function' ? container() : container; +} + +function getHasTransition(props) { + return props.children ? props.children.props.hasOwnProperty('in') : false; +} + +// A modal manager used to track and manage the state of open Modals. +// Modals don't open on the server so this won't conflict with concurrent requests. +const defaultManager = new ModalManager(); + +/** + * Modal is a lower-level construct that is leveraged by the following components: + * + * - [Dialog](/api/dialog/) + * - [Drawer](/api/drawer/) + * - [Menu](/api/menu/) + * - [Popover](/api/popover/) + * + * If you are creating a modal dialog, you probably want to use the [Dialog](/api/dialog/) component + * rather than directly using Modal. + * + * This component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals). + */ +const ModalUnstyled = React.forwardRef(function ModalUnstyled(props, ref) { + const { + BackdropComponent, + BackdropProps, + children, + classes: classesProp, + className, + closeAfterTransition = false, + component = 'div', + components = {}, + componentsProps = {}, + container, + disableAutoFocus = false, + disableEnforceFocus = false, + disableEscapeKeyDown = false, + disablePortal = false, + disableRestoreFocus = false, + disableScrollLock = false, + hideBackdrop = false, + keepMounted = false, + // private + // eslint-disable-next-line react/prop-types + manager = defaultManager, + onBackdropClick, + onClose, + onKeyDown, + open, + /* eslint-disable react/prop-types */ + theme, + onTransitionEnter, + onTransitionExited, + ...other + } = props; + + const [exited, setExited] = React.useState(true); + const modal = React.useRef({}); + const mountNodeRef = React.useRef(null); + const modalRef = React.useRef(null); + const handleRef = useForkRef(modalRef, ref); + const hasTransition = getHasTransition(props); + + const getDoc = () => ownerDocument(mountNodeRef.current); + const getModal = () => { + modal.current.modalRef = modalRef.current; + modal.current.mountNode = mountNodeRef.current; + return modal.current; + }; + + const handleMounted = () => { + manager.mount(getModal(), { disableScrollLock }); + + // Fix a bug on Chrome where the scroll isn't initially 0. + modalRef.current.scrollTop = 0; + }; + + const handleOpen = useEventCallback(() => { + const resolvedContainer = getContainer(container) || getDoc().body; + + manager.add(getModal(), resolvedContainer); + + // The element was already mounted. + if (modalRef.current) { + handleMounted(); + } + }); + + const isTopModal = React.useCallback(() => manager.isTopModal(getModal()), [manager]); + + const handlePortalRef = useEventCallback((node) => { + mountNodeRef.current = node; + + if (!node) { + return; + } + + if (open && isTopModal()) { + handleMounted(); + } else { + ariaHidden(modalRef.current, true); + } + }); + + const handleClose = React.useCallback(() => { + manager.remove(getModal()); + }, [manager]); + + React.useEffect(() => { + return () => { + handleClose(); + }; + }, [handleClose]); + + React.useEffect(() => { + if (open) { + handleOpen(); + } else if (!hasTransition || !closeAfterTransition) { + handleClose(); + } + }, [open, handleClose, hasTransition, closeAfterTransition, handleOpen]); + + const styleProps = { + ...props, + classes: classesProp, + closeAfterTransition, + disableAutoFocus, + disableEnforceFocus, + disableEscapeKeyDown, + disablePortal, + disableRestoreFocus, + disableScrollLock, + exited, + hideBackdrop, + keepMounted, + }; + + const classes = useUtilityClasses(styleProps); + + if (!keepMounted && !open && (!hasTransition || exited)) { + return null; + } + + const handleEnter = () => { + setExited(false); + + if (onTransitionEnter) { + onTransitionEnter(); + } + }; + + const handleExited = () => { + setExited(true); + + if (onTransitionExited) { + onTransitionExited(); + } + + if (closeAfterTransition) { + handleClose(); + } + }; + + const handleBackdropClick = (event) => { + if (event.target !== event.currentTarget) { + return; + } + + if (onBackdropClick) { + onBackdropClick(event); + } + + if (onClose) { + onClose(event, 'backdropClick'); + } + }; + + const handleKeyDown = (event) => { + if (onKeyDown) { + onKeyDown(event); + } + + // The handler doesn't take event.defaultPrevented into account: + // + // event.preventDefault() is meant to stop default behaviors like + // clicking a checkbox to check it, hitting a button to submit a form, + // and hitting left arrow to move the cursor in a text input etc. + // Only special HTML elements have these default behaviors. + if (event.key !== 'Escape' || !isTopModal()) { + return; + } + + if (!disableEscapeKeyDown) { + // Swallow the event, in case someone is listening for the escape key on the body. + event.stopPropagation(); + + if (onClose) { + onClose(event, 'escapeKeyDown'); + } + } + }; + + const childProps = {}; + if (children.props.tabIndex === undefined) { + childProps.tabIndex = children.props.tabIndex || '-1'; + } + + // It's a Transition like component + if (hasTransition) { + childProps.onEnter = createChainedFunction(handleEnter, children.props.onEnter); + childProps.onExited = createChainedFunction(handleExited, children.props.onExited); + } + + const Root = components.Root || component; + const rootProps = componentsProps.root || {}; + + return ( + + {/* + * Marking an element with the role presentation indicates to assistive technology + * that this element should be ignored; it exists to support the web application and + * is not meant for humans to interact with directly. + * https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-static-element-interactions.md + */} + + {!hideBackdrop && BackdropComponent ? ( + + ) : null} + + {React.cloneElement(children, childProps)} + + + + ); +}); + +ModalUnstyled.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the d.ts file and run "yarn proptypes" | + // ---------------------------------------------------------------------- + /** + * A backdrop component. This prop enables custom backdrop rendering. + */ + BackdropComponent: PropTypes.elementType, + /** + * Props applied to the [`BackdropUnstyled`](/api/backdrop-unstyled/) element. + */ + BackdropProps: PropTypes.object, + /** + * A single child content element. + */ + children: elementAcceptingRef.isRequired, + /** + * Override or extend the styles applied to the component. + */ + classes: PropTypes.object, + /** + * @ignore + */ + className: PropTypes.string, + /** + * When set to true the Modal waits until a nested Transition is completed before closing. + * @default false + */ + closeAfterTransition: PropTypes.bool, + /** + * The component used for the root node. + * Either a string to use a HTML element or a component. + */ + component: PropTypes.elementType, + /** + * The components used for each slot inside the Modal. + * Either a string to use a HTML element or a component. + * @default {} + */ + components: PropTypes.shape({ + Root: PropTypes.elementType, + }), + /** + * The props used for each slot inside the Modal. + * @default {} + */ + componentsProps: PropTypes.object, + /** + * An HTML element or function that returns one. + * The `container` will have the portal children appended to it. + * + * By default, it uses the body of the top-level document object, + * so it's simply `document.body` most of the time. + */ + container: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([ + HTMLElementType, + PropTypes.func, + ]), + /** + * If `true`, the modal will not automatically shift focus to itself when it opens, and + * replace it to the last focused element when it closes. + * This also works correctly with any modal children that have the `disableAutoFocus` prop. + * + * Generally this should never be set to `true` as it makes the modal less + * accessible to assistive technologies, like screen readers. + * @default false + */ + disableAutoFocus: PropTypes.bool, + /** + * If `true`, the modal will not prevent focus from leaving the modal while open. + * + * Generally this should never be set to `true` as it makes the modal less + * accessible to assistive technologies, like screen readers. + * @default false + */ + disableEnforceFocus: PropTypes.bool, + /** + * If `true`, hitting escape will not fire the `onClose` callback. + * @default false + */ + disableEscapeKeyDown: PropTypes.bool, + /** + * The `children` will be under the DOM hierarchy of the parent component. + * @default false + */ + disablePortal: PropTypes.bool, + /** + * If `true`, the modal will not restore focus to previously focused element once + * modal is hidden. + * @default false + */ + disableRestoreFocus: PropTypes.bool, + /** + * Disable the scroll lock behavior. + * @default false + */ + disableScrollLock: PropTypes.bool, + /** + * If `true`, the backdrop is not rendered. + * @default false + */ + hideBackdrop: PropTypes.bool, + /** + * Always keep the children in the DOM. + * This prop can be useful in SEO situation or + * when you want to maximize the responsiveness of the Modal. + * @default false + */ + keepMounted: PropTypes.bool, + /** + * Callback fired when the backdrop is clicked. + */ + onBackdropClick: PropTypes.func, + /** + * Callback fired when the component requests to be closed. + * The `reason` parameter can optionally be used to control the response to `onClose`. + * + * @param {object} event The event source of the callback. + * @param {string} reason Can be: `"escapeKeyDown"`, `"backdropClick"`. + */ + onClose: PropTypes.func, + /** + * @ignore + */ + onKeyDown: PropTypes.func, + /** + * If `true`, the component is shown. + */ + open: PropTypes.bool.isRequired, +}; + +export default ModalUnstyled; diff --git a/packages/material-ui-unstyled/src/ModalUnstyled/ModalUnstyled.test.js b/packages/material-ui-unstyled/src/ModalUnstyled/ModalUnstyled.test.js new file mode 100644 index 00000000000000..071cb48b22428f --- /dev/null +++ b/packages/material-ui-unstyled/src/ModalUnstyled/ModalUnstyled.test.js @@ -0,0 +1,75 @@ +import * as React from 'react'; +import { expect } from 'chai'; +import { createMount, createClientRender, describeConformance } from 'test/utils'; +import ModalUnstyled, { + modalUnstyledClasses as classes, +} from '@material-ui/unstyled/ModalUnstyled'; + +describe('', () => { + const mount = createMount(); + const render = createClientRender(); + let savedBodyStyle; + + before(() => { + savedBodyStyle = document.body.style; + }); + + beforeEach(() => { + document.body.setAttribute('style', savedBodyStyle); + }); + + describeConformance( + +

+ , + () => ({ + classes, + inheritComponent: 'div', + mount, + refInstanceof: window.HTMLDivElement, + testComponentPropWith: 'div', + skip: ['reactTestRenderer'], + }), + ); + + it('forwards style props on the Root component', () => { + let styleProps = null; + let theme = null; + + const Root = React.forwardRef( + ({ styleProps: stylePropsProp, theme: themeProp, ...rest }, ref) => { + styleProps = stylePropsProp; + theme = themeProp; + return ; + }, + ); + + render( + +
+ , + ); + + expect(styleProps).not.to.equal(null); + expect(theme).not.to.equal(null); + }); + + it('does not forward style props as DOM attributes if component slot is primitive', () => { + const elementRef = React.createRef(); + render( + +
+ , + ); + + const { current: element } = elementRef; + expect(element.getAttribute('styleProps')).to.equal(null); + expect(element.getAttribute('theme')).to.equal(null); + }); +}); diff --git a/packages/material-ui-unstyled/src/ModalUnstyled/index.d.ts b/packages/material-ui-unstyled/src/ModalUnstyled/index.d.ts new file mode 100644 index 00000000000000..f46c277c538f7f --- /dev/null +++ b/packages/material-ui-unstyled/src/ModalUnstyled/index.d.ts @@ -0,0 +1,8 @@ +export { default } from './ModalUnstyled'; +export * from './ModalUnstyled'; + +export { default as ModalManager } from './ModalManager'; +export * from './ModalManager'; + +export { default as modalUnstyledClasses } from './modalUnstyledClasses'; +export * from './modalUnstyledClasses'; diff --git a/packages/material-ui-unstyled/src/ModalUnstyled/index.js b/packages/material-ui-unstyled/src/ModalUnstyled/index.js new file mode 100644 index 00000000000000..6a1c50b5d29b00 --- /dev/null +++ b/packages/material-ui-unstyled/src/ModalUnstyled/index.js @@ -0,0 +1,5 @@ +export { default } from './ModalUnstyled'; + +export { default as ModalManager } from './ModalManager'; + +export { default as modalUnstyledClasses, getModalUtilityClass } from './modalUnstyledClasses'; diff --git a/packages/material-ui-unstyled/src/ModalUnstyled/modalUnstyledClasses.d.ts b/packages/material-ui-unstyled/src/ModalUnstyled/modalUnstyledClasses.d.ts new file mode 100644 index 00000000000000..31bb3cd6f1c179 --- /dev/null +++ b/packages/material-ui-unstyled/src/ModalUnstyled/modalUnstyledClasses.d.ts @@ -0,0 +1,9 @@ +import { ModalUnstyledClassKey } from './ModalUnstyled'; + +export type ModalUnstyledClasses = Record; + +declare const modalUnstyledClasses: ModalUnstyledClasses; + +export function getModalUtilityClass(slot: string): string; + +export default modalUnstyledClasses; diff --git a/packages/material-ui-unstyled/src/ModalUnstyled/modalUnstyledClasses.js b/packages/material-ui-unstyled/src/ModalUnstyled/modalUnstyledClasses.js new file mode 100644 index 00000000000000..18bba79a2cbdde --- /dev/null +++ b/packages/material-ui-unstyled/src/ModalUnstyled/modalUnstyledClasses.js @@ -0,0 +1,10 @@ +import generateUtilityClasses from '../generateUtilityClasses'; +import generateUtilityClass from '../generateUtilityClass'; + +export function getModalUtilityClass(slot) { + return generateUtilityClass('MuiModal', slot); +} + +const modalUnstyledClasses = generateUtilityClasses('MuiModal', ['root', 'hidden']); + +export default modalUnstyledClasses; diff --git a/packages/material-ui-unstyled/src/SliderUnstyled/SliderUnstyled.d.ts b/packages/material-ui-unstyled/src/SliderUnstyled/SliderUnstyled.d.ts index 36776195feae5c..7772164848d353 100644 --- a/packages/material-ui-unstyled/src/SliderUnstyled/SliderUnstyled.d.ts +++ b/packages/material-ui-unstyled/src/SliderUnstyled/SliderUnstyled.d.ts @@ -28,7 +28,6 @@ export interface SliderUnstyledTypeMap

0 && marks.some((mark) => mark.label), max, min, orientation, @@ -600,11 +602,9 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) { track, valueLabelDisplay, valueLabelFormat, - isRtl, - marked: marks.length > 0 && marks.some((mark) => mark.label), }; - const utilityClasses = useUtilityClasses({ ...styleProps, classes: classesProp }); + const classes = useUtilityClasses(styleProps); return ( {marks.map((mark, index) => { @@ -665,8 +665,8 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) { theme, })} style={{ ...style, ...markProps.style }} - className={clsx(utilityClasses.mark, markProps.className, { - [utilityClasses.markActive]: markActive, + className={clsx(classes.mark, markProps.className, { + [classes.markActive]: markActive, })} /> {mark.label != null ? ( @@ -683,8 +683,8 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) { theme, })} style={{ ...style, ...markLabelProps.style }} - className={clsx(utilityClasses.markLabel, markLabelProps.className, { - [utilityClasses.markLabelActive]: markActive, + className={clsx(classes.markLabel, markLabelProps.className, { + [classes.markLabelActive]: markActive, })} > {mark.label} @@ -713,7 +713,7 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) { open={open === index || active === index || valueLabelDisplay === 'on'} disabled={disabled} {...valueLabelProps} - className={clsx(utilityClasses.valueLabel, valueLabelProps.className)} + className={clsx(classes.valueLabel, valueLabelProps.className)} {...(!isHostComponent(ValueLabel) && { styleProps: { ...styleProps, ...valueLabelProps.styleProps }, theme, @@ -724,9 +724,9 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) { onMouseOver={handleMouseOver} onMouseLeave={handleMouseLeave} {...thumbProps} - className={clsx(utilityClasses.thumb, thumbProps.className, { - [utilityClasses.active]: active === index, - [utilityClasses.focusVisible]: focusVisible === index, + className={clsx(classes.thumb, thumbProps.className, { + [classes.active]: active === index, + [classes.focusVisible]: focusVisible === index, })} {...(!isHostComponent(Thumb) && { styleProps: { ...styleProps, ...thumbProps.styleProps }, @@ -815,7 +815,6 @@ SliderUnstyled.propTypes = { children: PropTypes.node, /** * Override or extend the styles applied to the component. - * @default {} */ classes: PropTypes.object, /** diff --git a/packages/material-ui-unstyled/src/index.d.ts b/packages/material-ui-unstyled/src/index.d.ts index 02de1ea2ba5aa7..5e2c860322674f 100644 --- a/packages/material-ui-unstyled/src/index.d.ts +++ b/packages/material-ui-unstyled/src/index.d.ts @@ -4,6 +4,9 @@ export * from './BackdropUnstyled'; export { default as BadgeUnstyled } from './BadgeUnstyled'; export * from './BadgeUnstyled'; +export { default as ModalUnstyled } from './ModalUnstyled'; +export * from './ModalUnstyled'; + export { default as SliderUnstyled } from './SliderUnstyled'; export * from './SliderUnstyled'; diff --git a/packages/material-ui-unstyled/src/index.js b/packages/material-ui-unstyled/src/index.js index 89131b6f9afdcf..87391679d5687a 100644 --- a/packages/material-ui-unstyled/src/index.js +++ b/packages/material-ui-unstyled/src/index.js @@ -7,6 +7,9 @@ export * from './BadgeUnstyled'; export { default as SliderUnstyled } from './SliderUnstyled'; export * from './SliderUnstyled'; +export { default as ModalUnstyled } from './ModalUnstyled'; +export * from './ModalUnstyled'; + export { default as Portal } from './Portal'; export { default as Unstable_TrapFocus } from './Unstable_TrapFocus'; diff --git a/packages/material-ui/src/Backdrop/Backdrop.d.ts b/packages/material-ui/src/Backdrop/Backdrop.d.ts index 77425a752956fc..c605deb49a5f56 100644 --- a/packages/material-ui/src/Backdrop/Backdrop.d.ts +++ b/packages/material-ui/src/Backdrop/Backdrop.d.ts @@ -17,7 +17,6 @@ export type BackdropTypeMap< Partial> & { /** * Override or extend the styles applied to the component. - * @default {} */ classes?: BackdropUnstyledTypeMap['props']['classes']; /** diff --git a/packages/material-ui/src/Backdrop/Backdrop.js b/packages/material-ui/src/Backdrop/Backdrop.js index dcefa5b2d45f57..e94eba3d755ed3 100644 --- a/packages/material-ui/src/Backdrop/Backdrop.js +++ b/packages/material-ui/src/Backdrop/Backdrop.js @@ -7,11 +7,7 @@ import experimentalStyled from '../styles/experimentalStyled'; import useThemeProps from '../styles/useThemeProps'; import Fade from '../Fade'; -const backdropClasses = { - ...backdropUnstyledClasses, -}; - -export { backdropClasses }; +export const backdropClasses = backdropUnstyledClasses; const overridesResolver = (props, styles) => { const { styleProps } = props; @@ -22,7 +18,7 @@ const overridesResolver = (props, styles) => { }; const extendUtilityClasses = (styleProps) => { - const { classes = {} } = styleProps; + const { classes } = styleProps; return classes; }; @@ -56,9 +52,9 @@ const BackdropRoot = experimentalStyled( const Backdrop = React.forwardRef(function Backdrop(inProps, ref) { const props = useThemeProps({ props: inProps, name: 'MuiBackdrop' }); const { + children, components = {}, componentsProps = {}, - children, className, invisible = false, open, @@ -112,7 +108,6 @@ Backdrop.propTypes = { children: PropTypes.node, /** * Override or extend the styles applied to the component. - * @default {} */ classes: PropTypes.object, /** diff --git a/packages/material-ui/src/Badge/Badge.d.ts b/packages/material-ui/src/Badge/Badge.d.ts index 96c8fe66a88bba..4f52f3f9b25897 100644 --- a/packages/material-ui/src/Badge/Badge.d.ts +++ b/packages/material-ui/src/Badge/Badge.d.ts @@ -19,7 +19,6 @@ export type BadgeTypeMap< props: P & { /** * Override or extend the styles applied to the component. - * @default {} */ classes?: BadgeUnstyledTypeMap['props']['classes'] & { /** Styles applied to the badge `span` element if `color="primary"`. */ diff --git a/packages/material-ui/src/Badge/Badge.js b/packages/material-ui/src/Badge/Badge.js index 1cb5beea83214f..a3ec7603775d47 100644 --- a/packages/material-ui/src/Badge/Badge.js +++ b/packages/material-ui/src/Badge/Badge.js @@ -11,13 +11,11 @@ import styled from '../styles/experimentalStyled'; import useThemeProps from '../styles/useThemeProps'; import capitalize from '../utils/capitalize'; -const badgeClasses = { +export const badgeClasses = { ...badgeUnstyledClasses, ...generateUtilityClasses('MuiBadge', ['colorError', 'colorPrimary', 'colorSecondary']), }; -export { badgeClasses }; - const RADIUS_STANDARD = 10; const RADIUS_DOT = 4; @@ -284,7 +282,6 @@ Badge.propTypes = { children: PropTypes.node, /** * Override or extend the styles applied to the component. - * @default {} */ classes: PropTypes.object, /** diff --git a/packages/material-ui/src/Modal/Modal.d.ts b/packages/material-ui/src/Modal/Modal.d.ts index 8011ba3ac3fae8..ab2f0f51063fab 100644 --- a/packages/material-ui/src/Modal/Modal.d.ts +++ b/packages/material-ui/src/Modal/Modal.d.ts @@ -1,106 +1,37 @@ import * as React from 'react'; -import { InternalStandardProps as StandardProps } from '..'; +import { SxProps } from '@material-ui/system'; +import { + ExtendModalUnstyledTypeMap, + ExtendModalUnstyled, + ModalUnstyledProps, +} from '@material-ui/unstyled/ModalUnstyled'; +import { Theme } from '../styles'; import { BackdropProps } from '../Backdrop'; -import { PortalProps } from '../Portal'; -export interface ModalProps - extends StandardProps, 'children'> { - /** - * A backdrop component. This prop enables custom backdrop rendering. - * @default SimpleBackdrop - */ - BackdropComponent?: React.ElementType; - /** - * Props applied to the [`Backdrop`](/api/backdrop/) element. - */ - BackdropProps?: Partial; - /** - * A single child content element. - */ - children: React.ReactElement; - /** - * When set to true the Modal waits until a nested Transition is completed before closing. - * @default false - */ - closeAfterTransition?: boolean; - /** - * An HTML element or function that returns one. - * The `container` will have the portal children appended to it. - * - * By default, it uses the body of the top-level document object, - * so it's simply `document.body` most of the time. - */ - container?: PortalProps['container']; - /** - * If `true`, the modal will not automatically shift focus to itself when it opens, and - * replace it to the last focused element when it closes. - * This also works correctly with any modal children that have the `disableAutoFocus` prop. - * - * Generally this should never be set to `true` as it makes the modal less - * accessible to assistive technologies, like screen readers. - * @default false - */ - disableAutoFocus?: boolean; - /** - * If `true`, the modal will not prevent focus from leaving the modal while open. - * - * Generally this should never be set to `true` as it makes the modal less - * accessible to assistive technologies, like screen readers. - * @default false - */ - disableEnforceFocus?: boolean; - /** - * If `true`, hitting escape will not fire the `onClose` callback. - * @default false - */ - disableEscapeKeyDown?: boolean; - /** - * The `children` will be under the DOM hierarchy of the parent component. - * @default false - */ - disablePortal?: PortalProps['disablePortal']; - /** - * If `true`, the modal will not restore focus to previously focused element once - * modal is hidden. - * @default false - */ - disableRestoreFocus?: boolean; - /** - * Disable the scroll lock behavior. - * @default false - */ - disableScrollLock?: boolean; - /** - * If `true`, the backdrop is not rendered. - * @default false - */ - hideBackdrop?: boolean; - /** - * Always keep the children in the DOM. - * This prop can be useful in SEO situation or - * when you want to maximize the responsiveness of the Modal. - * @default false - */ - keepMounted?: boolean; - /** - * Callback fired when the backdrop is clicked. - */ - onBackdropClick?: React.ReactEventHandler<{}>; - /** - * Callback fired when the component requests to be closed. - * The `reason` parameter can optionally be used to control the response to `onClose`. - * - * @param {object} event The event source of the callback. - * @param {string} reason Can be: `"escapeKeyDown"`, `"backdropClick"`. - */ - onClose?: { - bivarianceHack(event: {}, reason: 'backdropClick' | 'escapeKeyDown'): void; - }['bivarianceHack']; - /** - * If `true`, the component is shown. - */ - open: boolean; -} +export type ModalTypeMap = ExtendModalUnstyledTypeMap<{ + props: P & { + /** + * A backdrop component. This prop enables custom backdrop rendering. + * @default Backdrop + */ + BackdropComponent?: React.ElementType; + /** + * Props applied to the [`Backdrop`](/api/backdrop/) element. + */ + BackdropProps?: Partial; + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx?: SxProps; + }; + defaultComponent: D; +}>; + +type ModalRootProps = NonNullable['root']; + +export const ModalRoot: React.FC; + +export type ModalClassKey = keyof NonNullable; /** * Modal is a lower-level construct that is leveraged by the following components: @@ -123,6 +54,15 @@ export interface ModalProps * * - [Modal API](https://material-ui.com/api/modal/) */ -declare const Modal: React.ComponentType; +declare const Modal: ExtendModalUnstyled; + +export type ModalClasses = Record; + +export const modalClasses: ModalClasses; + +export type ModalProps< + D extends React.ElementType = ModalTypeMap['defaultComponent'], + P = {} +> = ModalUnstyledProps; export default Modal; diff --git a/packages/material-ui/src/Modal/Modal.js b/packages/material-ui/src/Modal/Modal.js index f3c334db36ffb1..028d9040f55ad5 100644 --- a/packages/material-ui/src/Modal/Modal.js +++ b/packages/material-ui/src/Modal/Modal.js @@ -1,44 +1,48 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import { getThemeProps, useTheme } from '@material-ui/styles'; -import { elementAcceptingRef, HTMLElementType } from '@material-ui/utils'; -import ownerDocument from '../utils/ownerDocument'; -import Portal from '../Portal'; -import createChainedFunction from '../utils/createChainedFunction'; -import useForkRef from '../utils/useForkRef'; -import useEventCallback from '../utils/useEventCallback'; -import zIndex from '../styles/zIndex'; -import ModalManager, { ariaHidden } from './ModalManager'; -import TrapFocus from '../Unstable_TrapFocus'; -import SimpleBackdrop from './SimpleBackdrop'; +import { isHostComponent } from '@material-ui/unstyled'; +import { deepmerge, elementAcceptingRef, HTMLElementType } from '@material-ui/utils'; +import ModalUnstyled, { modalUnstyledClasses } from '@material-ui/unstyled/ModalUnstyled'; +import experimentalStyled from '../styles/experimentalStyled'; +import useThemeProps from '../styles/useThemeProps'; +import Backdrop from '../Backdrop'; -function getContainer(container) { - return typeof container === 'function' ? container() : container; -} +export const modalClasses = modalUnstyledClasses; -function getHasTransition(props) { - return props.children ? props.children.props.hasOwnProperty('in') : false; -} +const overridesResolver = (props, styles) => { + const { styleProps } = props; -// A modal manager used to track and manage the state of open Modals. -// Modals don't open on the server so this won't conflict with concurrent requests. -const defaultManager = new ModalManager(); + return deepmerge(styles.root || {}, { + ...(!styleProps.open && styleProps.exited && styles.hidden), + }); +}; -export const styles = (theme) => ({ - /* Styles applied to the root element. */ - root: { - position: 'fixed', - zIndex: theme.zIndex.modal, - right: 0, - bottom: 0, - top: 0, - left: 0, +const extendUtilityClasses = (styleProps) => { + return styleProps.classes; +}; + +const ModalRoot = experimentalStyled( + 'div', + {}, + { + name: 'MuiModal', + slot: 'Root', + overridesResolver, }, +)(({ theme, styleProps }) => ({ + /* Styles applied to the root element. */ + position: 'fixed', + zIndex: theme.zIndex.modal, + right: 0, + bottom: 0, + top: 0, + left: 0, /* Styles applied to the root element if the `Modal` has exited. */ - hidden: { - visibility: 'hidden', - }, -}); + ...(!styleProps.open && + styleProps.exited && { + visibility: 'hidden', + }), +})); /** * Modal is a lower-level construct that is leveraged by the following components: @@ -54,14 +58,13 @@ export const styles = (theme) => ({ * This component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals). */ const Modal = React.forwardRef(function Modal(inProps, ref) { - const theme = useTheme(); - const props = getThemeProps({ name: 'MuiModal', props: inProps, theme }); + const props = useThemeProps({ name: 'MuiModal', props: inProps }); const { - BackdropComponent = SimpleBackdrop, - BackdropProps, - children, + BackdropComponent = Backdrop, closeAfterTransition = false, - container, + children, + components = {}, + componentsProps = {}, disableAutoFocus = false, disableEnforceFocus = false, disableEscapeKeyDown = false, @@ -70,184 +73,56 @@ const Modal = React.forwardRef(function Modal(inProps, ref) { disableScrollLock = false, hideBackdrop = false, keepMounted = false, - // private - // eslint-disable-next-line react/prop-types - manager = defaultManager, - onBackdropClick, - onClose, - onKeyDown, - open, ...other } = props; const [exited, setExited] = React.useState(true); - const modal = React.useRef({}); - const mountNodeRef = React.useRef(null); - const modalRef = React.useRef(null); - const handleRef = useForkRef(modalRef, ref); - const hasTransition = getHasTransition(props); - - const getDoc = () => ownerDocument(mountNodeRef.current); - const getModal = () => { - modal.current.modalRef = modalRef.current; - modal.current.mountNode = mountNodeRef.current; - return modal.current; - }; - - const handleMounted = () => { - manager.mount(getModal(), { disableScrollLock }); - - // Fix a bug on Chrome where the scroll isn't initially 0. - modalRef.current.scrollTop = 0; - }; - - const handleOpen = useEventCallback(() => { - const resolvedContainer = getContainer(container) || getDoc().body; - - manager.add(getModal(), resolvedContainer); - - // The element was already mounted. - if (modalRef.current) { - handleMounted(); - } - }); - - const isTopModal = React.useCallback(() => manager.isTopModal(getModal()), [manager]); - - const handlePortalRef = useEventCallback((node) => { - mountNodeRef.current = node; - - if (!node) { - return; - } - - if (open && isTopModal()) { - handleMounted(); - } else { - ariaHidden(modalRef.current, true); - } - }); - const handleClose = React.useCallback(() => { - manager.remove(getModal()); - }, [manager]); - - React.useEffect(() => { - return () => { - handleClose(); - }; - }, [handleClose]); - - React.useEffect(() => { - if (open) { - handleOpen(); - } else if (!hasTransition || !closeAfterTransition) { - handleClose(); - } - }, [open, handleClose, hasTransition, closeAfterTransition, handleOpen]); - - if (!keepMounted && !open && (!hasTransition || exited)) { - return null; - } - - const handleEnter = () => { - setExited(false); - }; - - const handleExited = () => { - setExited(true); - - if (closeAfterTransition) { - handleClose(); - } + const commonProps = { + BackdropComponent, + closeAfterTransition, + disableAutoFocus, + disableEnforceFocus, + disableEscapeKeyDown, + disablePortal, + disableRestoreFocus, + disableScrollLock, + hideBackdrop, + keepMounted, + // private + onTransitionEnter: () => setExited(false), + onTransitionExited: () => setExited(true), }; - const handleBackdropClick = (event) => { - if (event.target !== event.currentTarget) { - return; - } - - if (onBackdropClick) { - onBackdropClick(event); - } - - if (onClose) { - onClose(event, 'backdropClick'); - } + const styleProps = { + ...props, + ...commonProps, + exited, }; - const handleKeyDown = (event) => { - if (onKeyDown) { - onKeyDown(event); - } - - // The handler doesn't take event.defaultPrevented into account: - // - // event.preventDefault() is meant to stop default behaviors like - // clicking a checkbox to check it, hitting a button to submit a form, - // and hitting left arrow to move the cursor in a text input etc. - // Only special HTML elements have these default behaviors. - if (event.key !== 'Escape' || !isTopModal()) { - return; - } - - if (!disableEscapeKeyDown) { - // Swallow the event, in case someone is listening for the escape key on the body. - event.stopPropagation(); - - if (onClose) { - onClose(event, 'escapeKeyDown'); - } - } - }; - - const inlineStyle = styles(theme || { zIndex }); - const childProps = {}; - if (children.props.tabIndex === undefined) { - childProps.tabIndex = children.props.tabIndex || '-1'; - } - - // It's a Transition like component - if (hasTransition) { - childProps.onEnter = createChainedFunction(handleEnter, children.props.onEnter); - childProps.onExited = createChainedFunction(handleExited, children.props.onExited); - } + const classes = extendUtilityClasses(styleProps); return ( - - {/* - * Marking an element with the role presentation indicates to assistive technology - * that this element should be ignored; it exists to support the web application and - * is not meant for humans to interact with directly. - * https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-static-element-interactions.md - */} -

- {hideBackdrop ? null : ( - - )} - - - {React.cloneElement(children, childProps)} - -
- + + {children} + ); }); @@ -258,7 +133,7 @@ Modal.propTypes = { // ---------------------------------------------------------------------- /** * A backdrop component. This prop enables custom backdrop rendering. - * @default SimpleBackdrop + * @default Backdrop */ BackdropComponent: PropTypes.elementType, /** @@ -269,11 +144,28 @@ Modal.propTypes = { * A single child content element. */ children: elementAcceptingRef.isRequired, + /** + * Override or extend the styles applied to the component. + */ + classes: PropTypes.object, /** * When set to true the Modal waits until a nested Transition is completed before closing. * @default false */ closeAfterTransition: PropTypes.bool, + /** + * The components used for each slot inside the Modal. + * Either a string to use a HTML element or a component. + * @default {} + */ + components: PropTypes.shape({ + Root: PropTypes.elementType, + }), + /** + * The props used for each slot inside the Modal. + * @default {} + */ + componentsProps: PropTypes.object, /** * An HTML element or function that returns one. * The `container` will have the portal children appended to it. @@ -348,18 +240,14 @@ Modal.propTypes = { * @param {string} reason Can be: `"escapeKeyDown"`, `"backdropClick"`. */ onClose: PropTypes.func, - /** - * @ignore - */ - onKeyDown: PropTypes.func, /** * If `true`, the component is shown. */ open: PropTypes.bool.isRequired, /** - * @ignore + * The system prop that allows defining system overrides as well as additional CSS styles. */ - style: PropTypes.object, + sx: PropTypes.object, }; export default Modal; diff --git a/packages/material-ui/src/Modal/Modal.test.js b/packages/material-ui/src/Modal/Modal.test.js index 0cd3d1b50dcfbd..643560aa239f69 100644 --- a/packages/material-ui/src/Modal/Modal.test.js +++ b/packages/material-ui/src/Modal/Modal.test.js @@ -9,17 +9,17 @@ import { fireEvent, within, createMount, - describeConformance, + describeConformanceV5, } from 'test/utils'; import { createMuiTheme } from '@material-ui/core/styles'; import { ThemeProvider } from '@material-ui/styles'; -import Fade from '../Fade'; -import Backdrop from '../Backdrop'; -import Modal from './Modal'; +import Fade from '@material-ui/core/Fade'; +import Backdrop from '@material-ui/core/Backdrop'; +import Modal, { modalClasses as classes } from '@material-ui/core/Modal'; describe('', () => { - const mount = createMount({ strict: true }); const render = createClientRender(); + const mount = createMount({ strict: true }); let savedBodyStyle; before(() => { @@ -30,17 +30,25 @@ describe('', () => { document.body.setAttribute('style', savedBodyStyle); }); - describeConformance( + describeConformanceV5(
, () => ({ + classes, inheritComponent: 'div', + render, mount, + muiName: 'MuiModal', refInstanceof: window.HTMLDivElement, + testVariantProps: { hideBackdrop: true }, skip: [ 'rootClass', 'componentProp', + 'componentsProp', + // Can not test this because everything is applied to second element + 'themeDefaultProps', + 'themeStyleOverrides', // https://github.com/facebook/react/issues/11565 'reactTestRenderer', ], diff --git a/packages/material-ui/src/Modal/SimpleBackdrop.js b/packages/material-ui/src/Modal/SimpleBackdrop.js deleted file mode 100644 index 5d7645952b7def..00000000000000 --- a/packages/material-ui/src/Modal/SimpleBackdrop.js +++ /dev/null @@ -1,54 +0,0 @@ -import * as React from 'react'; -import PropTypes from 'prop-types'; - -export const styles = { - /* Styles applied to the root element. */ - root: { - zIndex: -1, - position: 'fixed', - right: 0, - bottom: 0, - top: 0, - left: 0, - backgroundColor: 'rgba(0, 0, 0, 0.5)', - WebkitTapHighlightColor: 'transparent', - }, - /* Styles applied to the root element if `invisible={true}`. */ - invisible: { - backgroundColor: 'transparent', - }, -}; - -/** - * @ignore - internal component. - */ -const SimpleBackdrop = React.forwardRef(function SimpleBackdrop(props, ref) { - const { invisible = false, open, ...other } = props; - - return open ? ( -
- ) : null; -}); - -SimpleBackdrop.propTypes = { - /** - * If `true`, the backdrop is invisible. - * It can be used when rendering a popover or a custom select component. - */ - invisible: PropTypes.bool, - /** - * If `true`, the component is shown. - */ - open: PropTypes.bool.isRequired, -}; - -export default SimpleBackdrop; diff --git a/packages/material-ui/src/Modal/index.d.ts b/packages/material-ui/src/Modal/index.d.ts index 4fd1d7c9b6f99b..59d1074f096836 100644 --- a/packages/material-ui/src/Modal/index.d.ts +++ b/packages/material-ui/src/Modal/index.d.ts @@ -1,4 +1,4 @@ +export * from '@material-ui/unstyled/ModalUnstyled'; // exporting ModalManager + export { default } from './Modal'; export * from './Modal'; -export { default as ModalManager } from './ModalManager'; -export * from './ModalManager'; diff --git a/packages/material-ui/src/Modal/index.js b/packages/material-ui/src/Modal/index.js index 86979640642557..3e825141545223 100644 --- a/packages/material-ui/src/Modal/index.js +++ b/packages/material-ui/src/Modal/index.js @@ -1,2 +1,4 @@ +export * from '@material-ui/unstyled/ModalUnstyled'; + export { default } from './Modal'; -export { default as ModalManager } from './ModalManager'; +export * from './Modal'; diff --git a/packages/material-ui/src/Slider/Slider.d.ts b/packages/material-ui/src/Slider/Slider.d.ts index bd7c31bf2c0109..15bfbd97ede072 100644 --- a/packages/material-ui/src/Slider/Slider.d.ts +++ b/packages/material-ui/src/Slider/Slider.d.ts @@ -20,7 +20,6 @@ export type SliderTypeMap< color?: 'primary' | 'secondary'; /** * Override or extend the styles applied to the component. - * @default {} */ classes?: SliderUnstyledTypeMap['props']['classes'] & { /** Class name applied to the root element if `color="primary"`. */ diff --git a/packages/material-ui/src/Slider/Slider.js b/packages/material-ui/src/Slider/Slider.js index ff1f61389903ad..6eebcfece1f80a 100644 --- a/packages/material-ui/src/Slider/Slider.js +++ b/packages/material-ui/src/Slider/Slider.js @@ -464,7 +464,6 @@ Slider.propTypes = { children: PropTypes.node, /** * Override or extend the styles applied to the component. - * @default {} */ classes: PropTypes.object, /** diff --git a/packages/material-ui/src/styles/components.d.ts b/packages/material-ui/src/styles/components.d.ts index 4a3400db9ba23d..b32342ffe07ac4 100644 --- a/packages/material-ui/src/styles/components.d.ts +++ b/packages/material-ui/src/styles/components.d.ts @@ -279,6 +279,10 @@ export interface Components { defaultProps?: ComponentsProps['MuiMobileStepper']; styleOverrides?: ComponentsOverrides['MuiMobileStepper']; }; + MuiModal?: { + defaultProps?: ComponentsProps['MuiModal']; + styleOverrides?: ComponentsOverrides['MuiModal']; + }; MuiNativeSelect?: { defaultProps?: ComponentsProps['MuiNativeSelect']; styleOverrides?: ComponentsOverrides['MuiNativeSelect']; diff --git a/packages/material-ui/src/styles/overrides.d.ts b/packages/material-ui/src/styles/overrides.d.ts index 01d040594dcd31..7f3e97c5615701 100644 --- a/packages/material-ui/src/styles/overrides.d.ts +++ b/packages/material-ui/src/styles/overrides.d.ts @@ -64,6 +64,7 @@ import { ListSubheaderClassKey } from '../ListSubheader'; import { MenuClassKey } from '../Menu'; import { MenuItemClassKey } from '../MenuItem'; import { MobileStepperClassKey } from '../MobileStepper'; +import { ModalClassKey } from '../Modal'; import { NativeSelectClassKey } from '../NativeSelect'; import { OutlinedInputClassKey } from '../OutlinedInput'; import { PaginationClassKey } from '../Pagination'; @@ -181,6 +182,7 @@ export interface ComponentNameToClassKey { MuiMenu: MenuClassKey; MuiMenuItem: MenuItemClassKey; MuiMobileStepper: MobileStepperClassKey; + MuiModal: ModalClassKey; MuiNativeSelect: NativeSelectClassKey; MuiOutlinedInput: OutlinedInputClassKey; MuiPagination: PaginationClassKey;