From ad850021c97f165498f4712ca951ef67f4c6116d Mon Sep 17 00:00:00 2001 From: Siriwat K Date: Mon, 6 May 2024 18:39:22 +0700 Subject: [PATCH] [material-ui] Migrate components to support CSS extraction (#42001) --- .github/workflows/ci.yml | 2 + apps/pigment-css-next-app/next.config.js | 27 ++ apps/pigment-css-next-app/package.json | 4 +- docs/pages/material-ui/api/filled-input.json | 2 +- docs/pages/material-ui/api/input.json | 2 +- package.json | 2 +- .../src/LoadingButton/LoadingButton.js | 186 ++++++++----- packages/mui-lab/src/zero-styled/index.ts | 8 + .../src/Breadcrumbs/BreadcrumbCollapsed.js | 2 +- packages/mui-material/src/Button/Button.js | 2 +- .../mui-material/src/Checkbox/Checkbox.js | 2 + .../mui-material/src/Collapse/Collapse.js | 103 ++++--- packages/mui-material/src/Dialog/Dialog.js | 169 +++++++----- .../src/DialogActions/DialogActions.js | 22 +- .../src/DialogContent/DialogContent.js | 24 +- .../DialogContentText/DialogContentText.js | 6 +- .../src/DialogTitle/DialogTitle.js | 5 +- packages/mui-material/src/Drawer/Drawer.js | 114 +++++--- packages/mui-material/src/Fab/Fab.js | 2 +- .../src/FilledInput/FilledInput.d.ts | 1 + .../src/FilledInput/FilledInput.js | 254 +++++++++++------- .../src/FormHelperText/FormHelperText.js | 5 +- .../mui-material/src/FormLabel/FormLabel.js | 39 ++- .../src/FormLabel/FormLabel.test.js | 10 + packages/mui-material/src/Grow/Grow.js | 4 +- packages/mui-material/src/Icon/Icon.js | 95 +++++-- .../mui-material/src/ImageList/ImageList.js | 5 +- .../src/ImageListItem/ImageListItem.js | 5 +- .../src/ImageListItemBar/ImageListItemBar.js | 5 +- packages/mui-material/src/Input/Input.d.ts | 1 + packages/mui-material/src/Input/Input.js | 136 ++++++---- .../src/InputAdornment/InputAdornment.js | 59 ++-- .../mui-material/src/InputBase/InputBase.js | 84 +++--- .../mui-material/src/InputLabel/InputLabel.js | 178 +++++++----- packages/mui-material/src/Link/Link.js | 134 ++++++--- .../src/Link/getTextDecoration.test.js | 30 +-- .../src/Link/getTextDecoration.ts | 27 +- packages/mui-material/src/List/List.js | 31 ++- .../mui-material/src/ListItem/ListItem.js | 5 +- .../src/ListItemAvatar/ListItemAvatar.js | 5 +- .../src/ListItemButton/ListItemButton.js | 6 +- .../src/ListItemIcon/ListItemIcon.js | 20 +- .../ListItemSecondaryAction.js | 5 +- .../src/ListItemText/ListItemText.js | 5 +- .../src/ListSubheader/ListSubheader.js | 9 +- packages/mui-material/src/Menu/Menu.js | 6 +- .../mui-material/src/MenuItem/MenuItem.js | 62 +++-- .../src/NativeSelect/NativeSelectInput.js | 127 +++++---- .../src/OutlinedInput/NotchedOutline.js | 88 +++--- .../src/OutlinedInput/OutlinedInput.js | 138 ++++++---- .../mui-material/src/Pagination/Pagination.js | 5 +- packages/mui-material/src/Paper/Paper.js | 74 +++-- packages/mui-material/src/Radio/Radio.js | 4 +- .../mui-material/src/Radio/RadioButtonIcon.js | 2 +- packages/mui-material/src/Rating/Rating.js | 6 +- packages/mui-material/src/Select/Select.js | 3 +- .../mui-material/src/Select/SelectInput.js | 17 +- .../mui-material/src/Skeleton/Skeleton.js | 204 ++++++++------ .../mui-material/src/Snackbar/Snackbar.js | 84 +++--- .../src/SnackbarContent/SnackbarContent.js | 5 +- .../mui-material/src/SpeedDial/SpeedDial.js | 102 ++++--- .../src/SpeedDialAction/SpeedDialAction.js | 71 +++-- .../src/SpeedDialIcon/SpeedDialIcon.js | 44 ++- .../src/SwipeableDrawer/SwipeArea.js | 73 +++-- packages/mui-material/src/Tab/Tab.js | 167 ++++++++---- .../src/TabScrollButton/TabScrollButton.js | 38 ++- packages/mui-material/src/Table/Table.js | 5 +- .../mui-material/src/TableBody/TableBody.js | 5 +- .../mui-material/src/TableCell/TableCell.js | 5 +- .../src/TableContainer/TableContainer.js | 5 +- .../src/TableFooter/TableFooter.js | 5 +- .../mui-material/src/TableHead/TableHead.js | 5 +- .../src/TablePagination/TablePagination.js | 5 +- .../mui-material/src/TableRow/TableRow.js | 5 +- .../src/TableSortLabel/TableSortLabel.js | 5 +- packages/mui-material/src/Tabs/Tabs.js | 148 ++++++---- .../mui-material/src/TextField/TextField.js | 5 +- packages/mui-material/src/Toolbar/Toolbar.js | 67 +++-- packages/mui-material/src/Tooltip/Tooltip.js | 244 +++++++++++------ .../mui-material/src/Typography/Typography.js | 116 +++++--- .../mui-material/src/internal/SwitchBase.js | 45 +++- pnpm-lock.yaml | 87 ++++-- 82 files changed, 2547 insertions(+), 1372 deletions(-) create mode 100644 packages/mui-lab/src/zero-styled/index.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3d726a90bd2a34..f6ce2f60aa3677 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,6 +38,8 @@ jobs: cache: 'pnpm' # https://github.com/actions/setup-node/blob/main/docs/advanced-usage.md#caching-packages-dependencies - run: pnpm install - run: pnpm build:ci + env: + NODE_OPTIONS: --max_old_space_size=4096 - run: pnpm release:changelog env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/apps/pigment-css-next-app/next.config.js b/apps/pigment-css-next-app/next.config.js index 70facd067ef4ec..a2187d6190e6ba 100644 --- a/apps/pigment-css-next-app/next.config.js +++ b/apps/pigment-css-next-app/next.config.js @@ -96,6 +96,13 @@ theme.getColorSchemeSelector = (colorScheme) => { return `@media (prefers-color-scheme: ${colorScheme})`; }; +function innerNoop() { + return null; +} +function outerNoop() { + return innerNoop; +} + /** * @type {PigmentOptions} */ @@ -104,6 +111,26 @@ const pigmentOptions = { transformLibraries: ['local-ui-lib'], sourceMap: true, displayName: true, + overrideContext: (context) => { + if (!context.$RefreshSig$) { + context.$RefreshSig$ = outerNoop; + } + return { + ...context, + require: (id) => { + if (id === '@mui/styled-engine' || id === '@mui/styled-engine-sc') { + return { + __esModule: true, + default: () => () => () => null, + internal_processStyles: () => {}, + keyframes: () => '', + css: () => '', + }; + } + return context.require(id); + }, + }; + }, }; /** @type {import('next').NextConfig} */ diff --git a/apps/pigment-css-next-app/package.json b/apps/pigment-css-next-app/package.json index d6122741013d76..69291fb793bb3b 100644 --- a/apps/pigment-css-next-app/package.json +++ b/apps/pigment-css-next-app/package.json @@ -9,7 +9,7 @@ "clean": "rimraf .next" }, "dependencies": { - "@pigment-css/react": "^0.0.9", + "@pigment-css/react": "^0.0.10", "@mui/utils": "workspace:^", "@mui/base": "workspace:^", "@mui/lab": "workspace:^", @@ -24,7 +24,7 @@ "next": "latest" }, "devDependencies": { - "@pigment-css/nextjs-plugin": "^0.0.9", + "@pigment-css/nextjs-plugin": "^0.0.10", "@types/node": "^20.5.7", "@types/react": "^18.2.55", "@types/react-dom": "^18.3.0", diff --git a/docs/pages/material-ui/api/filled-input.json b/docs/pages/material-ui/api/filled-input.json index edf8016b29aa3a..0422d195c86877 100644 --- a/docs/pages/material-ui/api/filled-input.json +++ b/docs/pages/material-ui/api/filled-input.json @@ -19,7 +19,7 @@ }, "defaultValue": { "type": { "name": "any" } }, "disabled": { "type": { "name": "bool" } }, - "disableUnderline": { "type": { "name": "bool" } }, + "disableUnderline": { "type": { "name": "bool" }, "default": "false" }, "endAdornment": { "type": { "name": "node" } }, "error": { "type": { "name": "bool" } }, "fullWidth": { "type": { "name": "bool" }, "default": "false" }, diff --git a/docs/pages/material-ui/api/input.json b/docs/pages/material-ui/api/input.json index 313bb2bfc69c1d..79a1bcd9305cb5 100644 --- a/docs/pages/material-ui/api/input.json +++ b/docs/pages/material-ui/api/input.json @@ -19,7 +19,7 @@ }, "defaultValue": { "type": { "name": "any" } }, "disabled": { "type": { "name": "bool" } }, - "disableUnderline": { "type": { "name": "bool" } }, + "disableUnderline": { "type": { "name": "bool" }, "default": "false" }, "endAdornment": { "type": { "name": "node" } }, "error": { "type": { "name": "bool" } }, "fullWidth": { "type": { "name": "bool" }, "default": "false" }, diff --git a/package.json b/package.json index 31f1876ba23581..7325aa1b54dedb 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "@mui/utils": "workspace:^", "@next/eslint-plugin-next": "^14.2.3", "@octokit/rest": "^20.1.0", - "@pigment-css/react": "^0.0.9", + "@pigment-css/react": "^0.0.10", "@playwright/test": "1.43.1", "@types/enzyme": "^3.10.18", "@types/fs-extra": "^11.0.4", diff --git a/packages/mui-lab/src/LoadingButton/LoadingButton.js b/packages/mui-lab/src/LoadingButton/LoadingButton.js index 98ca8e4e90c730..47920a507f3ecd 100644 --- a/packages/mui-lab/src/LoadingButton/LoadingButton.js +++ b/packages/mui-lab/src/LoadingButton/LoadingButton.js @@ -4,13 +4,15 @@ import PropTypes from 'prop-types'; import { chainPropTypes } from '@mui/utils'; import { capitalize, unstable_useId as useId } from '@mui/material/utils'; import { unstable_composeClasses as composeClasses } from '@mui/base'; -import { styled, useThemeProps } from '@mui/material/styles'; import Button from '@mui/material/Button'; import { ButtonGroupContext } from '@mui/material/ButtonGroup'; import CircularProgress from '@mui/material/CircularProgress'; import resolveProps from '@mui/utils/resolveProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import loadingButtonClasses, { getLoadingButtonUtilityClass } from './loadingButtonClasses'; +const useThemeProps = createUseThemeProps('MuiLoadingButton'); + const useUtilityClasses = (ownerState) => { const { loading, loadingPosition, classes } = ownerState; @@ -32,7 +34,7 @@ const useUtilityClasses = (ownerState) => { }; }; -// TODO use `import { rootShouldForwardProp } from '../styles/styled';` once move to core +// TODO use `import rootShouldForwardProp from '../styles/rootShouldForwardProp';` once move to core const rootShouldForwardProp = (prop) => prop !== 'ownerState' && prop !== 'theme' && prop !== 'sx' && prop !== 'as' && prop !== 'classes'; const LoadingButtonRoot = styled(Button, { @@ -50,7 +52,7 @@ const LoadingButtonRoot = styled(Button, { }, ]; }, -})(({ ownerState, theme }) => ({ +})(({ theme }) => ({ [`& .${loadingButtonClasses.startIconLoadingStart}, & .${loadingButtonClasses.endIconLoadingEnd}`]: { transition: theme.transitions.create(['opacity'], { @@ -58,36 +60,47 @@ const LoadingButtonRoot = styled(Button, { }), opacity: 0, }, - ...(ownerState.loadingPosition === 'center' && { - transition: theme.transitions.create(['background-color', 'box-shadow', 'border-color'], { - duration: theme.transitions.duration.short, - }), - [`&.${loadingButtonClasses.loading}`]: { - color: 'transparent', - }, - }), - ...(ownerState.loadingPosition === 'start' && - ownerState.fullWidth && { - [`& .${loadingButtonClasses.startIconLoadingStart}, & .${loadingButtonClasses.endIconLoadingEnd}`]: - { - transition: theme.transitions.create(['opacity'], { - duration: theme.transitions.duration.short, - }), - opacity: 0, - marginRight: -8, - }, - }), - ...(ownerState.loadingPosition === 'end' && - ownerState.fullWidth && { - [`& .${loadingButtonClasses.startIconLoadingStart}, & .${loadingButtonClasses.endIconLoadingEnd}`]: - { - transition: theme.transitions.create(['opacity'], { - duration: theme.transitions.duration.short, - }), - opacity: 0, - marginLeft: -8, + variants: [ + { + props: { + loadingPosition: 'center', + }, + style: { + transition: theme.transitions.create(['background-color', 'box-shadow', 'border-color'], { + duration: theme.transitions.duration.short, + }), + [`&.${loadingButtonClasses.loading}`]: { + color: 'transparent', }, - }), + }, + }, + { + props: ({ ownerState }) => ownerState.loadingPosition === 'start' && ownerState.fullWidth, + style: { + [`& .${loadingButtonClasses.startIconLoadingStart}, & .${loadingButtonClasses.endIconLoadingEnd}`]: + { + transition: theme.transitions.create(['opacity'], { + duration: theme.transitions.duration.short, + }), + opacity: 0, + marginRight: -8, + }, + }, + }, + { + props: ({ ownerState }) => ownerState.loadingPosition === 'end' && ownerState.fullWidth, + style: { + [`& .${loadingButtonClasses.startIconLoadingStart}, & .${loadingButtonClasses.endIconLoadingEnd}`]: + { + transition: theme.transitions.create(['opacity'], { + duration: theme.transitions.duration.short, + }), + opacity: 0, + marginLeft: -8, + }, + }, + }, + ], })); const LoadingButtonLoadingIndicator = styled('span', { @@ -100,41 +113,86 @@ const LoadingButtonLoadingIndicator = styled('span', { styles[`loadingIndicator${capitalize(ownerState.loadingPosition)}`], ]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ position: 'absolute', visibility: 'visible', display: 'flex', - ...(ownerState.loadingPosition === 'start' && - (ownerState.variant === 'outlined' || ownerState.variant === 'contained') && { - left: ownerState.size === 'small' ? 10 : 14, - }), - ...(ownerState.loadingPosition === 'start' && - ownerState.variant === 'text' && { - left: 6, - }), - ...(ownerState.loadingPosition === 'center' && { - left: '50%', - transform: 'translate(-50%)', - color: (theme.vars || theme).palette.action.disabled, - }), - ...(ownerState.loadingPosition === 'end' && - (ownerState.variant === 'outlined' || ownerState.variant === 'contained') && { - right: ownerState.size === 'small' ? 10 : 14, - }), - ...(ownerState.loadingPosition === 'end' && - ownerState.variant === 'text' && { - right: 6, - }), - ...(ownerState.loadingPosition === 'start' && - ownerState.fullWidth && { - position: 'relative', - left: -10, - }), - ...(ownerState.loadingPosition === 'end' && - ownerState.fullWidth && { - position: 'relative', - right: -10, - }), + variants: [ + { + props: { + loadingPosition: 'start', + size: 'small', + }, + style: { + left: 10, + }, + }, + { + props: ({ loadingPosition, ownerState }) => + loadingPosition === 'start' && ownerState.size !== 'small', + style: { + left: 14, + }, + }, + { + props: { + variant: 'text', + loadingPosition: 'start', + }, + style: { + left: 6, + }, + }, + { + props: { + loadingPosition: 'center', + }, + style: { + left: '50%', + transform: 'translate(-50%)', + color: (theme.vars || theme).palette.action.disabled, + }, + }, + { + props: { + loadingPosition: 'end', + size: 'small', + }, + style: { + right: 10, + }, + }, + { + props: ({ loadingPosition, ownerState }) => + loadingPosition === 'end' && ownerState.size !== 'small', + style: { + right: 14, + }, + }, + { + props: { + variant: 'text', + loadingPosition: 'end', + }, + style: { + right: 6, + }, + }, + { + props: ({ ownerState }) => ownerState.loadingPosition === 'start' && ownerState.fullWidth, + style: { + position: 'relative', + left: -10, + }, + }, + { + props: ({ ownerState }) => ownerState.loadingPosition === 'end' && ownerState.fullWidth, + style: { + position: 'relative', + right: -10, + }, + }, + ], })); const LoadingButton = React.forwardRef(function LoadingButton(inProps, ref) { diff --git a/packages/mui-lab/src/zero-styled/index.ts b/packages/mui-lab/src/zero-styled/index.ts new file mode 100644 index 00000000000000..ac070a82614dfd --- /dev/null +++ b/packages/mui-lab/src/zero-styled/index.ts @@ -0,0 +1,8 @@ +import { useThemeProps } from '@mui/material/styles'; + +export { styled } from '@mui/material/styles'; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export function createUseThemeProps(name: string) { + return useThemeProps; +} diff --git a/packages/mui-material/src/Breadcrumbs/BreadcrumbCollapsed.js b/packages/mui-material/src/Breadcrumbs/BreadcrumbCollapsed.js index 2b208d529df3a1..7a5dc972423cba 100644 --- a/packages/mui-material/src/Breadcrumbs/BreadcrumbCollapsed.js +++ b/packages/mui-material/src/Breadcrumbs/BreadcrumbCollapsed.js @@ -2,7 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { emphasize } from '@mui/system/colorManipulator'; -import styled from '../styles/styled'; +import { styled } from '../zero-styled'; import MoreHorizIcon from '../internal/svg-icons/MoreHoriz'; import ButtonBase from '../ButtonBase'; diff --git a/packages/mui-material/src/Button/Button.js b/packages/mui-material/src/Button/Button.js index 822a5a7ca3ad7d..3caec7c29e7aab 100644 --- a/packages/mui-material/src/Button/Button.js +++ b/packages/mui-material/src/Button/Button.js @@ -5,7 +5,7 @@ import clsx from 'clsx'; import resolveProps from '@mui/utils/resolveProps'; import composeClasses from '@mui/utils/composeClasses'; import { alpha } from '@mui/system/colorManipulator'; -import { rootShouldForwardProp } from '../styles/styled'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; import { styled, createUseThemeProps } from '../zero-styled'; import ButtonBase from '../ButtonBase'; import capitalize from '../utils/capitalize'; diff --git a/packages/mui-material/src/Checkbox/Checkbox.js b/packages/mui-material/src/Checkbox/Checkbox.js index 3687c1376e3d9c..342ecab31729ea 100644 --- a/packages/mui-material/src/Checkbox/Checkbox.js +++ b/packages/mui-material/src/Checkbox/Checkbox.js @@ -117,6 +117,7 @@ const Checkbox = React.forwardRef(function Checkbox(inProps, ref) { indeterminateIcon: indeterminateIconProp = defaultIndeterminateIcon, inputProps, size = 'medium', + disableRipple = false, className, ...other } = props; @@ -126,6 +127,7 @@ const Checkbox = React.forwardRef(function Checkbox(inProps, ref) { const ownerState = { ...props, + disableRipple, color, indeterminate, size, diff --git a/packages/mui-material/src/Collapse/Collapse.js b/packages/mui-material/src/Collapse/Collapse.js index 27bc19224a42f5..1b459620da0610 100644 --- a/packages/mui-material/src/Collapse/Collapse.js +++ b/packages/mui-material/src/Collapse/Collapse.js @@ -6,14 +6,15 @@ import { Transition } from 'react-transition-group'; import useTimeout from '@mui/utils/useTimeout'; import elementTypeAcceptingRef from '@mui/utils/elementTypeAcceptingRef'; import composeClasses from '@mui/utils/composeClasses'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import { duration } from '../styles/createTransitions'; import { getTransitionProps } from '../transitions/utils'; import useTheme from '../styles/useTheme'; import { useForkRef } from '../utils'; import { getCollapseUtilityClass } from './collapseClasses'; +const useThemeProps = createUseThemeProps('MuiCollapse'); + const useUtilityClasses = (ownerState) => { const { orientation, classes } = ownerState; @@ -44,54 +45,88 @@ const CollapseRoot = styled('div', { styles.hidden, ]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ height: 0, overflow: 'hidden', transition: theme.transitions.create('height'), - ...(ownerState.orientation === 'horizontal' && { - height: 'auto', - width: 0, - transition: theme.transitions.create('width'), - }), - ...(ownerState.state === 'entered' && { - height: 'auto', - overflow: 'visible', - ...(ownerState.orientation === 'horizontal' && { - width: 'auto', - }), - }), - ...(ownerState.state === 'exited' && - !ownerState.in && - ownerState.collapsedSize === '0px' && { - visibility: 'hidden', - }), + variants: [ + { + props: { + orientation: 'horizontal', + }, + style: { + height: 'auto', + width: 0, + transition: theme.transitions.create('width'), + }, + }, + { + props: { + state: 'entered', + }, + style: { + height: 'auto', + overflow: 'visible', + }, + }, + { + props: { + state: 'entered', + orientation: 'horizontal', + }, + style: { + width: 'auto', + }, + }, + { + props: ({ ownerState }) => + ownerState.state === 'exited' && !ownerState.in && ownerState.collapsedSize === '0px', + style: { + visibility: 'hidden', + }, + }, + ], })); const CollapseWrapper = styled('div', { name: 'MuiCollapse', slot: 'Wrapper', overridesResolver: (props, styles) => styles.wrapper, -})(({ ownerState }) => ({ +})({ // Hack to get children with a negative margin to not falsify the height computation. display: 'flex', width: '100%', - ...(ownerState.orientation === 'horizontal' && { - width: 'auto', - height: '100%', - }), -})); + variants: [ + { + props: { + orientation: 'horizontal', + }, + style: { + width: 'auto', + height: '100%', + }, + }, + ], +}); const CollapseWrapperInner = styled('div', { name: 'MuiCollapse', slot: 'WrapperInner', overridesResolver: (props, styles) => styles.wrapperInner, -})(({ ownerState }) => ({ +})({ width: '100%', - ...(ownerState.orientation === 'horizontal' && { - width: 'auto', - height: '100%', - }), -})); + variants: [ + { + props: { + orientation: 'horizontal', + }, + style: { + width: 'auto', + height: '100%', + }, + }, + ], +}); /** * The Collapse transition is used by the @@ -418,6 +453,8 @@ Collapse.propTypes /* remove-proptypes */ = { ]), }; -Collapse.muiSupportAuto = true; +if (Collapse) { + Collapse.muiSupportAuto = true; +} export default Collapse; diff --git a/packages/mui-material/src/Dialog/Dialog.js b/packages/mui-material/src/Dialog/Dialog.js index b88a9103d01389..f92ff6b029842a 100644 --- a/packages/mui-material/src/Dialog/Dialog.js +++ b/packages/mui-material/src/Dialog/Dialog.js @@ -8,12 +8,13 @@ import capitalize from '../utils/capitalize'; import Modal from '../Modal'; import Fade from '../Fade'; import Paper from '../Paper'; -import useThemeProps from '../styles/useThemeProps'; -import styled from '../styles/styled'; import dialogClasses, { getDialogUtilityClass } from './dialogClasses'; import DialogContext from './DialogContext'; import Backdrop from '../Backdrop'; import useTheme from '../styles/useTheme'; +import { styled, createUseThemeProps } from '../zero-styled'; + +const useThemeProps = createUseThemeProps('MuiDialog'); const DialogBackdrop = styled(Backdrop, { name: 'MuiDialog', @@ -61,31 +62,43 @@ const DialogContainer = styled('div', { return [styles.container, styles[`scroll${capitalize(ownerState.scroll)}`]]; }, -})(({ ownerState }) => ({ +})({ height: '100%', '@media print': { height: 'auto', }, // We disable the focus ring for mouse, touch and keyboard users. outline: 0, - ...(ownerState.scroll === 'paper' && { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - }), - ...(ownerState.scroll === 'body' && { - overflowY: 'auto', - overflowX: 'hidden', - textAlign: 'center', - '&::after': { - content: '""', - display: 'inline-block', - verticalAlign: 'middle', - height: '100%', - width: '0', + variants: [ + { + props: { + scroll: 'paper', + }, + style: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + }, }, - }), -})); + { + props: { + scroll: 'body', + }, + style: { + overflowY: 'auto', + overflowX: 'hidden', + textAlign: 'center', + '&::after': { + content: '""', + display: 'inline-block', + verticalAlign: 'middle', + height: '100%', + width: '0', + }, + }, + }, + ], +}); const DialogPaper = styled(Paper, { name: 'MuiDialog', @@ -101,7 +114,7 @@ const DialogPaper = styled(Paper, { ownerState.fullScreen && styles.paperFullScreen, ]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ margin: 32, position: 'relative', overflowY: 'auto', // Fix IE11 issue, to remove at some point. @@ -109,54 +122,84 @@ const DialogPaper = styled(Paper, { overflowY: 'visible', boxShadow: 'none', }, - ...(ownerState.scroll === 'paper' && { - display: 'flex', - flexDirection: 'column', - maxHeight: 'calc(100% - 64px)', - }), - ...(ownerState.scroll === 'body' && { - display: 'inline-block', - verticalAlign: 'middle', - textAlign: 'left', // 'initial' doesn't work on IE11 - }), - ...(!ownerState.maxWidth && { - maxWidth: 'calc(100% - 64px)', - }), - ...(ownerState.maxWidth === 'xs' && { - maxWidth: - theme.breakpoints.unit === 'px' - ? Math.max(theme.breakpoints.values.xs, 444) - : `max(${theme.breakpoints.values.xs}${theme.breakpoints.unit}, 444px)`, - [`&.${dialogClasses.paperScrollBody}`]: { - [theme.breakpoints.down(Math.max(theme.breakpoints.values.xs, 444) + 32 * 2)]: { + variants: [ + { + props: { + scroll: 'paper', + }, + style: { + display: 'flex', + flexDirection: 'column', + maxHeight: 'calc(100% - 64px)', + }, + }, + { + props: { + scroll: 'body', + }, + style: { + display: 'inline-block', + verticalAlign: 'middle', + textAlign: 'left', // 'initial' doesn't work on IE11 + }, + }, + { + props: ({ ownerState }) => !ownerState.maxWidth, + style: { maxWidth: 'calc(100% - 64px)', }, }, - }), - ...(ownerState.maxWidth && - ownerState.maxWidth !== 'xs' && { - maxWidth: `${theme.breakpoints.values[ownerState.maxWidth]}${theme.breakpoints.unit}`, - [`&.${dialogClasses.paperScrollBody}`]: { - [theme.breakpoints.down(theme.breakpoints.values[ownerState.maxWidth] + 32 * 2)]: { - maxWidth: 'calc(100% - 64px)', + { + props: { + maxWidth: 'xs', + }, + style: { + maxWidth: + theme.breakpoints.unit === 'px' + ? Math.max(theme.breakpoints.values.xs, 444) + : `max(${theme.breakpoints.values.xs}${theme.breakpoints.unit}, 444px)`, + [`&.${dialogClasses.paperScrollBody}`]: { + [theme.breakpoints.down(Math.max(theme.breakpoints.values.xs, 444) + 32 * 2)]: { + maxWidth: 'calc(100% - 64px)', + }, + }, + }, + }, + ...Object.keys(theme.breakpoints.values) + .filter((maxWidth) => maxWidth !== 'xs') + .map((maxWidth) => ({ + props: { maxWidth }, + style: { + maxWidth: `${theme.breakpoints.values[maxWidth]}${theme.breakpoints.unit}`, + [`&.${dialogClasses.paperScrollBody}`]: { + [theme.breakpoints.down(theme.breakpoints.values[maxWidth] + 32 * 2)]: { + maxWidth: 'calc(100% - 64px)', + }, + }, + }, + })), + { + props: ({ ownerState }) => ownerState.fullWidth, + style: { + width: 'calc(100% - 64px)', + }, + }, + { + props: ({ ownerState }) => ownerState.fullScreen, + style: { + margin: 0, + width: '100%', + maxWidth: '100%', + height: '100%', + maxHeight: 'none', + borderRadius: 0, + [`&.${dialogClasses.paperScrollBody}`]: { + margin: 0, + maxWidth: '100%', }, }, - }), - ...(ownerState.fullWidth && { - width: 'calc(100% - 64px)', - }), - ...(ownerState.fullScreen && { - margin: 0, - width: '100%', - maxWidth: '100%', - height: '100%', - maxHeight: 'none', - borderRadius: 0, - [`&.${dialogClasses.paperScrollBody}`]: { - margin: 0, - maxWidth: '100%', }, - }), + ], })); /** diff --git a/packages/mui-material/src/DialogActions/DialogActions.js b/packages/mui-material/src/DialogActions/DialogActions.js index a66fb25bf2008b..b57f1dab955c8d 100644 --- a/packages/mui-material/src/DialogActions/DialogActions.js +++ b/packages/mui-material/src/DialogActions/DialogActions.js @@ -3,10 +3,11 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getDialogActionsUtilityClass } from './dialogActionsClasses'; +const useThemeProps = createUseThemeProps('MuiDialogActions'); + const useUtilityClasses = (ownerState) => { const { classes, disableSpacing } = ownerState; @@ -25,18 +26,23 @@ const DialogActionsRoot = styled('div', { return [styles.root, !ownerState.disableSpacing && styles.spacing]; }, -})(({ ownerState }) => ({ +})({ display: 'flex', alignItems: 'center', padding: 8, justifyContent: 'flex-end', flex: '0 0 auto', - ...(!ownerState.disableSpacing && { - '& > :not(style) ~ :not(style)': { - marginLeft: 8, + variants: [ + { + props: ({ ownerState }) => !ownerState.disableSpacing, + style: { + '& > :not(style) ~ :not(style)': { + marginLeft: 8, + }, + }, }, - }), -})); + ], +}); const DialogActions = React.forwardRef(function DialogActions(inProps, ref) { const props = useThemeProps({ diff --git a/packages/mui-material/src/DialogContent/DialogContent.js b/packages/mui-material/src/DialogContent/DialogContent.js index ec0367c918df4c..2a9d222ef44c2b 100644 --- a/packages/mui-material/src/DialogContent/DialogContent.js +++ b/packages/mui-material/src/DialogContent/DialogContent.js @@ -3,11 +3,12 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getDialogContentUtilityClass } from './dialogContentClasses'; import dialogTitleClasses from '../DialogTitle/dialogTitleClasses'; +const useThemeProps = createUseThemeProps('MuiDialogContent'); + const useUtilityClasses = (ownerState) => { const { classes, dividers } = ownerState; @@ -26,23 +27,30 @@ const DialogContentRoot = styled('div', { return [styles.root, ownerState.dividers && styles.dividers]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ flex: '1 1 auto', // Add iOS momentum scrolling for iOS < 13.0 WebkitOverflowScrolling: 'touch', overflowY: 'auto', padding: '20px 24px', - ...(ownerState.dividers - ? { + variants: [ + { + props: ({ ownerState }) => ownerState.dividers, + style: { padding: '16px 24px', borderTop: `1px solid ${(theme.vars || theme).palette.divider}`, borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, - } - : { + }, + }, + { + props: ({ ownerState }) => !ownerState.dividers, + style: { [`.${dialogTitleClasses.root} + &`]: { paddingTop: 0, }, - }), + }, + }, + ], })); const DialogContent = React.forwardRef(function DialogContent(inProps, ref) { diff --git a/packages/mui-material/src/DialogContentText/DialogContentText.js b/packages/mui-material/src/DialogContentText/DialogContentText.js index c6c8cabc6056ed..ebb915bb144f50 100644 --- a/packages/mui-material/src/DialogContentText/DialogContentText.js +++ b/packages/mui-material/src/DialogContentText/DialogContentText.js @@ -3,11 +3,13 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; -import styled, { rootShouldForwardProp } from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; +import { styled, createUseThemeProps } from '../zero-styled'; import Typography from '../Typography'; import { getDialogContentTextUtilityClass } from './dialogContentTextClasses'; +const useThemeProps = createUseThemeProps('MuiDialogContentText'); + const useUtilityClasses = (ownerState) => { const { classes } = ownerState; diff --git a/packages/mui-material/src/DialogTitle/DialogTitle.js b/packages/mui-material/src/DialogTitle/DialogTitle.js index aa160274950623..9c59a9e706d32c 100644 --- a/packages/mui-material/src/DialogTitle/DialogTitle.js +++ b/packages/mui-material/src/DialogTitle/DialogTitle.js @@ -4,11 +4,12 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import Typography from '../Typography'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getDialogTitleUtilityClass } from './dialogTitleClasses'; import DialogContext from '../Dialog/DialogContext'; +const useThemeProps = createUseThemeProps('MuiDialogTitle'); + const useUtilityClasses = (ownerState) => { const { classes } = ownerState; diff --git a/packages/mui-material/src/Drawer/Drawer.js b/packages/mui-material/src/Drawer/Drawer.js index 1849bd69a9d238..e3d5f686f503c1 100644 --- a/packages/mui-material/src/Drawer/Drawer.js +++ b/packages/mui-material/src/Drawer/Drawer.js @@ -10,10 +10,12 @@ import Slide from '../Slide'; import Paper from '../Paper'; import capitalize from '../utils/capitalize'; import useTheme from '../styles/useTheme'; -import useThemeProps from '../styles/useThemeProps'; -import styled, { rootShouldForwardProp } from '../styles/styled'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getDrawerUtilityClass } from './drawerClasses'; +const useThemeProps = createUseThemeProps('MuiDrawer'); + const overridesResolver = (props, styles) => { const { ownerState } = props; @@ -72,7 +74,7 @@ const DrawerPaper = styled(Paper, { styles[`paperAnchorDocked${capitalize(ownerState.anchor)}`], ]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ overflowY: 'auto', display: 'flex', flexDirection: 'column', @@ -88,43 +90,75 @@ const DrawerPaper = styled(Paper, { // At some point, it would be better to keep it for keyboard users. // :focus-ring CSS pseudo-class will help. outline: 0, - ...(ownerState.anchor === 'left' && { - left: 0, - }), - ...(ownerState.anchor === 'top' && { - top: 0, - left: 0, - right: 0, - height: 'auto', - maxHeight: '100%', - }), - ...(ownerState.anchor === 'right' && { - right: 0, - }), - ...(ownerState.anchor === 'bottom' && { - top: 'auto', - left: 0, - bottom: 0, - right: 0, - height: 'auto', - maxHeight: '100%', - }), - ...(ownerState.anchor === 'left' && - ownerState.variant !== 'temporary' && { - borderRight: `1px solid ${(theme.vars || theme).palette.divider}`, - }), - ...(ownerState.anchor === 'top' && - ownerState.variant !== 'temporary' && { - borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, - }), - ...(ownerState.anchor === 'right' && - ownerState.variant !== 'temporary' && { - borderLeft: `1px solid ${(theme.vars || theme).palette.divider}`, - }), - ...(ownerState.anchor === 'bottom' && - ownerState.variant !== 'temporary' && { - borderTop: `1px solid ${(theme.vars || theme).palette.divider}`, - }), + variants: [ + { + props: { + anchor: 'left', + }, + style: { + left: 0, + }, + }, + { + props: { + anchor: 'top', + }, + style: { + top: 0, + left: 0, + right: 0, + height: 'auto', + maxHeight: '100%', + }, + }, + { + props: { + anchor: 'right', + }, + style: { + right: 0, + }, + }, + { + props: { + anchor: 'bottom', + }, + style: { + top: 'auto', + left: 0, + bottom: 0, + right: 0, + height: 'auto', + maxHeight: '100%', + }, + }, + { + props: ({ ownerState }) => ownerState.anchor === 'left' && ownerState.variant !== 'temporary', + style: { + borderRight: `1px solid ${(theme.vars || theme).palette.divider}`, + }, + }, + { + props: ({ ownerState }) => ownerState.anchor === 'top' && ownerState.variant !== 'temporary', + style: { + borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, + }, + }, + { + props: ({ ownerState }) => + ownerState.anchor === 'right' && ownerState.variant !== 'temporary', + style: { + borderLeft: `1px solid ${(theme.vars || theme).palette.divider}`, + }, + }, + { + props: ({ ownerState }) => + ownerState.anchor === 'bottom' && ownerState.variant !== 'temporary', + style: { + borderTop: `1px solid ${(theme.vars || theme).palette.divider}`, + }, + }, + ], })); const oppositeDirection = { diff --git a/packages/mui-material/src/Fab/Fab.js b/packages/mui-material/src/Fab/Fab.js index bf80527ebd2f57..ddd85203a3d2b3 100644 --- a/packages/mui-material/src/Fab/Fab.js +++ b/packages/mui-material/src/Fab/Fab.js @@ -6,7 +6,7 @@ import composeClasses from '@mui/utils/composeClasses'; import ButtonBase from '../ButtonBase'; import capitalize from '../utils/capitalize'; import fabClasses, { getFabUtilityClass } from './fabClasses'; -import { rootShouldForwardProp } from '../styles/styled'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; import { styled, createUseThemeProps } from '../zero-styled'; const useThemeProps = createUseThemeProps('MuiFab'); diff --git a/packages/mui-material/src/FilledInput/FilledInput.d.ts b/packages/mui-material/src/FilledInput/FilledInput.d.ts index c9caa77ac2b6c3..b54d7c165608ec 100644 --- a/packages/mui-material/src/FilledInput/FilledInput.d.ts +++ b/packages/mui-material/src/FilledInput/FilledInput.d.ts @@ -17,6 +17,7 @@ export interface FilledInputProps extends StandardProps { hiddenLabel?: boolean; /** * If `true`, the input will not have an underline. + * @default false */ disableUnderline?: boolean; /** diff --git a/packages/mui-material/src/FilledInput/FilledInput.js b/packages/mui-material/src/FilledInput/FilledInput.js index 9e2de297107310..2173dc9a565410 100644 --- a/packages/mui-material/src/FilledInput/FilledInput.js +++ b/packages/mui-material/src/FilledInput/FilledInput.js @@ -5,16 +5,18 @@ import refType from '@mui/utils/refType'; import PropTypes from 'prop-types'; import composeClasses from '@mui/utils/composeClasses'; import InputBase from '../InputBase'; -import styled, { rootShouldForwardProp } from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; +import { styled, createUseThemeProps } from '../zero-styled'; import filledInputClasses, { getFilledInputUtilityClass } from './filledInputClasses'; import { rootOverridesResolver as inputBaseRootOverridesResolver, inputOverridesResolver as inputBaseInputOverridesResolver, InputBaseRoot, - InputBaseComponent as InputBaseInput, + InputBaseInput, } from '../InputBase/InputBase'; +const useThemeProps = createUseThemeProps('MuiFilledInput'); + const useUtilityClasses = (ownerState) => { const { classes, disableUnderline } = ownerState; @@ -42,7 +44,7 @@ const FilledInputRoot = styled(InputBaseRoot, { !ownerState.disableUnderline && styles.underline, ]; }, -})(({ theme, ownerState }) => { +})(({ theme }) => { const light = theme.palette.mode === 'light'; const bottomLineColor = light ? 'rgba(0, 0, 0, 0.42)' : 'rgba(255, 255, 255, 0.7)'; const backgroundColor = light ? 'rgba(0, 0, 0, 0.06)' : 'rgba(255, 255, 255, 0.09)'; @@ -70,80 +72,113 @@ const FilledInputRoot = styled(InputBaseRoot, { [`&.${filledInputClasses.disabled}`]: { backgroundColor: theme.vars ? theme.vars.palette.FilledInput.disabledBg : disabledBackground, }, - ...(!ownerState.disableUnderline && { - '&::after': { - borderBottom: `2px solid ${ - (theme.vars || theme).palette[ownerState.color || 'primary']?.main - }`, - left: 0, - bottom: 0, - // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242 - content: '""', - position: 'absolute', - right: 0, - transform: 'scaleX(0)', - transition: theme.transitions.create('transform', { - duration: theme.transitions.duration.shorter, - easing: theme.transitions.easing.easeOut, - }), - pointerEvents: 'none', // Transparent to the hover style. + variants: [ + { + props: ({ ownerState }) => !ownerState.disableUnderline, + style: { + '&::after': { + left: 0, + bottom: 0, + // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242 + content: '""', + position: 'absolute', + right: 0, + transform: 'scaleX(0)', + transition: theme.transitions.create('transform', { + duration: theme.transitions.duration.shorter, + easing: theme.transitions.easing.easeOut, + }), + pointerEvents: 'none', // Transparent to the hover style. + }, + [`&.${filledInputClasses.focused}:after`]: { + // translateX(0) is a workaround for Safari transform scale bug + // See https://github.com/mui/material-ui/issues/31766 + transform: 'scaleX(1) translateX(0)', + }, + [`&.${filledInputClasses.error}`]: { + '&::before, &::after': { + borderBottomColor: (theme.vars || theme).palette.error.main, + }, + }, + '&::before': { + borderBottom: `1px solid ${ + theme.vars + ? `rgba(${theme.vars.palette.common.onBackgroundChannel} / ${theme.vars.opacity.inputUnderline})` + : bottomLineColor + }`, + left: 0, + bottom: 0, + // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242 + content: '"\\00a0"', + position: 'absolute', + right: 0, + transition: theme.transitions.create('border-bottom-color', { + duration: theme.transitions.duration.shorter, + }), + pointerEvents: 'none', // Transparent to the hover style. + }, + [`&:hover:not(.${filledInputClasses.disabled}, .${filledInputClasses.error}):before`]: { + borderBottom: `1px solid ${(theme.vars || theme).palette.text.primary}`, + }, + [`&.${filledInputClasses.disabled}:before`]: { + borderBottomStyle: 'dotted', + }, + }, }, - [`&.${filledInputClasses.focused}:after`]: { - // translateX(0) is a workaround for Safari transform scale bug - // See https://github.com/mui/material-ui/issues/31766 - transform: 'scaleX(1) translateX(0)', + ...Object.entries(theme.palette) + .filter(([, value]) => value.main) // check all the used fields in the style below + .map(([color]) => ({ + props: { + disableUnderline: false, + color, + }, + style: { + '&::after': { + borderBottom: `2px solid ${(theme.vars || theme).palette[color]?.main}`, + }, + }, + })), + { + props: ({ ownerState }) => ownerState.startAdornment, + style: { + paddingLeft: 12, + }, }, - [`&.${filledInputClasses.error}`]: { - '&::before, &::after': { - borderBottomColor: (theme.vars || theme).palette.error.main, + { + props: ({ ownerState }) => ownerState.endAdornment, + style: { + paddingRight: 12, }, }, - '&::before': { - borderBottom: `1px solid ${ - theme.vars - ? `rgba(${theme.vars.palette.common.onBackgroundChannel} / ${theme.vars.opacity.inputUnderline})` - : bottomLineColor - }`, - left: 0, - bottom: 0, - // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242 - content: '"\\00a0"', - position: 'absolute', - right: 0, - transition: theme.transitions.create('border-bottom-color', { - duration: theme.transitions.duration.shorter, - }), - pointerEvents: 'none', // Transparent to the hover style. + { + props: ({ ownerState }) => ownerState.multiline, + style: { + padding: '25px 12px 8px', + }, }, - [`&:hover:not(.${filledInputClasses.disabled}, .${filledInputClasses.error}):before`]: { - borderBottom: `1px solid ${(theme.vars || theme).palette.text.primary}`, + { + props: ({ ownerState, size }) => ownerState.multiline && size === 'small', + style: { + paddingTop: 21, + paddingBottom: 4, + }, }, - [`&.${filledInputClasses.disabled}:before`]: { - borderBottomStyle: 'dotted', + { + props: ({ ownerState }) => ownerState.multiline && ownerState.hiddenLabel, + style: { + paddingTop: 16, + paddingBottom: 17, + }, }, - }), - ...(ownerState.startAdornment && { - paddingLeft: 12, - }), - ...(ownerState.endAdornment && { - paddingRight: 12, - }), - ...(ownerState.multiline && { - padding: '25px 12px 8px', - ...(ownerState.size === 'small' && { - paddingTop: 21, - paddingBottom: 4, - }), - ...(ownerState.hiddenLabel && { - paddingTop: 16, - paddingBottom: 17, - }), - ...(ownerState.hiddenLabel && - ownerState.size === 'small' && { + { + props: ({ ownerState }) => + ownerState.multiline && ownerState.hiddenLabel && ownerState.size === 'small', + style: { paddingTop: 8, paddingBottom: 9, - }), - }), + }, + }, + ], }; }); @@ -151,7 +186,7 @@ const FilledInputInput = styled(InputBaseInput, { name: 'MuiFilledInput', slot: 'Input', overridesResolver: inputBaseInputOverridesResolver, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ paddingTop: 25, paddingRight: 12, paddingBottom: 8, @@ -178,38 +213,59 @@ const FilledInputInput = styled(InputBaseInput, { }, }, }), - ...(ownerState.size === 'small' && { - paddingTop: 21, - paddingBottom: 4, - }), - ...(ownerState.hiddenLabel && { - paddingTop: 16, - paddingBottom: 17, - }), - ...(ownerState.startAdornment && { - paddingLeft: 0, - }), - ...(ownerState.endAdornment && { - paddingRight: 0, - }), - ...(ownerState.hiddenLabel && - ownerState.size === 'small' && { - paddingTop: 8, - paddingBottom: 9, - }), - ...(ownerState.multiline && { - paddingTop: 0, - paddingBottom: 0, - paddingLeft: 0, - paddingRight: 0, - }), + variants: [ + { + props: { + size: 'small', + }, + style: { + paddingTop: 21, + paddingBottom: 4, + }, + }, + { + props: ({ ownerState }) => ownerState.hiddenLabel, + style: { + paddingTop: 16, + paddingBottom: 17, + }, + }, + { + props: ({ ownerState }) => ownerState.startAdornment, + style: { + paddingLeft: 0, + }, + }, + { + props: ({ ownerState }) => ownerState.endAdornment, + style: { + paddingRight: 0, + }, + }, + { + props: ({ ownerState }) => ownerState.hiddenLabel && ownerState.size === 'small', + style: { + paddingTop: 8, + paddingBottom: 9, + }, + }, + { + props: ({ ownerState }) => ownerState.multiline, + style: { + paddingTop: 0, + paddingBottom: 0, + paddingLeft: 0, + paddingRight: 0, + }, + }, + ], })); const FilledInput = React.forwardRef(function FilledInput(inProps, ref) { const props = useThemeProps({ props: inProps, name: 'MuiFilledInput' }); const { - disableUnderline, + disableUnderline = false, components = {}, componentsProps: componentsPropsProp, fullWidth = false, @@ -224,6 +280,7 @@ const FilledInput = React.forwardRef(function FilledInput(inProps, ref) { const ownerState = { ...props, + disableUnderline, fullWidth, inputComponent, multiline, @@ -321,6 +378,7 @@ FilledInput.propTypes /* remove-proptypes */ = { disabled: PropTypes.bool, /** * If `true`, the input will not have an underline. + * @default false */ disableUnderline: PropTypes.bool, /** @@ -457,6 +515,8 @@ FilledInput.propTypes /* remove-proptypes */ = { value: PropTypes.any, }; -FilledInput.muiName = 'Input'; +if (FilledInput) { + FilledInput.muiName = 'Input'; +} export default FilledInput; diff --git a/packages/mui-material/src/FormHelperText/FormHelperText.js b/packages/mui-material/src/FormHelperText/FormHelperText.js index 9a1a133b958a95..e20bfe5649ca73 100644 --- a/packages/mui-material/src/FormHelperText/FormHelperText.js +++ b/packages/mui-material/src/FormHelperText/FormHelperText.js @@ -5,10 +5,11 @@ import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import formControlState from '../FormControl/formControlState'; import useFormControl from '../FormControl/useFormControl'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import capitalize from '../utils/capitalize'; import formHelperTextClasses, { getFormHelperTextUtilityClasses } from './formHelperTextClasses'; -import useThemeProps from '../styles/useThemeProps'; + +const useThemeProps = createUseThemeProps('MuiFormHelperText'); const useUtilityClasses = (ownerState) => { const { classes, contained, size, disabled, error, filled, focused, required } = ownerState; diff --git a/packages/mui-material/src/FormLabel/FormLabel.js b/packages/mui-material/src/FormLabel/FormLabel.js index ba9826f0d7f52a..1eb1fcad5dfc2a 100644 --- a/packages/mui-material/src/FormLabel/FormLabel.js +++ b/packages/mui-material/src/FormLabel/FormLabel.js @@ -6,10 +6,11 @@ import composeClasses from '@mui/utils/composeClasses'; import formControlState from '../FormControl/formControlState'; import useFormControl from '../FormControl/useFormControl'; import capitalize from '../utils/capitalize'; -import useThemeProps from '../styles/useThemeProps'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import formLabelClasses, { getFormLabelUtilityClasses } from './formLabelClasses'; +const useThemeProps = createUseThemeProps('MuiFormLabel'); + const useUtilityClasses = (ownerState) => { const { classes, color, focused, disabled, error, filled, required } = ownerState; const slots = { @@ -38,21 +39,35 @@ export const FormLabelRoot = styled('label', { ...(ownerState.filled && styles.filled), }; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ color: (theme.vars || theme).palette.text.secondary, ...theme.typography.body1, lineHeight: '1.4375em', padding: 0, position: 'relative', - [`&.${formLabelClasses.focused}`]: { - color: (theme.vars || theme).palette[ownerState.color].main, - }, - [`&.${formLabelClasses.disabled}`]: { - color: (theme.vars || theme).palette.text.disabled, - }, - [`&.${formLabelClasses.error}`]: { - color: (theme.vars || theme).palette.error.main, - }, + variants: [ + ...Object.entries(theme.palette) + .filter(([, value]) => value.main) + .map(([color]) => ({ + props: { color }, + style: { + [`&.${formLabelClasses.focused}`]: { + color: (theme.vars || theme).palette[color].main, + }, + }, + })), + { + props: {}, + style: { + [`&.${formLabelClasses.disabled}`]: { + color: (theme.vars || theme).palette.text.disabled, + }, + [`&.${formLabelClasses.error}`]: { + color: (theme.vars || theme).palette.error.main, + }, + }, + }, + ], })); const AsteriskComponent = styled('span', { diff --git a/packages/mui-material/src/FormLabel/FormLabel.test.js b/packages/mui-material/src/FormLabel/FormLabel.test.js index 412b5f6a59b433..9852498cc78aac 100644 --- a/packages/mui-material/src/FormLabel/FormLabel.test.js +++ b/packages/mui-material/src/FormLabel/FormLabel.test.js @@ -180,5 +180,15 @@ describe('', () => { color: hexToRgb(defaultTheme.palette.error.main), }); }); + + it('should have the disabled class and style, even when focused', () => { + const { container, getByTestId } = render( + , + ); + expect(container.querySelector(`.${classes.colorSecondary}`)).to.have.class(classes.disabled); + expect(getByTestId('FormLabel')).toHaveComputedStyle({ + color: defaultTheme.palette.text.disabled, + }); + }); }); }); diff --git a/packages/mui-material/src/Grow/Grow.js b/packages/mui-material/src/Grow/Grow.js index 77866f1f107765..670d4582c4ba86 100644 --- a/packages/mui-material/src/Grow/Grow.js +++ b/packages/mui-material/src/Grow/Grow.js @@ -288,6 +288,8 @@ Grow.propTypes /* remove-proptypes */ = { ]), }; -Grow.muiSupportAuto = true; +if (Grow) { + Grow.muiSupportAuto = true; +} export default Grow; diff --git a/packages/mui-material/src/Icon/Icon.js b/packages/mui-material/src/Icon/Icon.js index 8a8dbbc9344e4e..b6b029436f3761 100644 --- a/packages/mui-material/src/Icon/Icon.js +++ b/packages/mui-material/src/Icon/Icon.js @@ -3,11 +3,12 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; import capitalize from '../utils/capitalize'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getIconUtilityClass } from './iconClasses'; +const useThemeProps = createUseThemeProps('MuiIcon'); + const useUtilityClasses = (ownerState) => { const { color, fontSize, classes } = ownerState; @@ -34,7 +35,7 @@ const IconRoot = styled('span', { styles[`fontSize${capitalize(ownerState.fontSize)}`], ]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ userSelect: 'none', width: '1em', height: '1em', @@ -44,24 +45,72 @@ const IconRoot = styled('span', { display: 'inline-block', // allow overflow hidden to take action textAlign: 'center', // support non-square icon flexShrink: 0, - fontSize: { - inherit: 'inherit', - small: theme.typography.pxToRem(20), - medium: theme.typography.pxToRem(24), - large: theme.typography.pxToRem(36), - }[ownerState.fontSize], - // TODO v5 deprecate, v6 remove for sx - color: { - primary: (theme.vars || theme).palette.primary.main, - secondary: (theme.vars || theme).palette.secondary.main, - info: (theme.vars || theme).palette.info.main, - success: (theme.vars || theme).palette.success.main, - warning: (theme.vars || theme).palette.warning.main, - action: (theme.vars || theme).palette.action.active, - error: (theme.vars || theme).palette.error.main, - disabled: (theme.vars || theme).palette.action.disabled, - inherit: undefined, - }[ownerState.color], + variants: [ + { + props: { + fontSize: 'inherit', + }, + style: { + fontSize: 'inherit', + }, + }, + { + props: { + fontSize: 'small', + }, + style: { + fontSize: theme.typography.pxToRem(20), + }, + }, + { + props: { + fontSize: 'medium', + }, + style: { + fontSize: theme.typography.pxToRem(24), + }, + }, + { + props: { + fontSize: 'large', + }, + style: { + fontSize: theme.typography.pxToRem(36), + }, + }, + { + props: { + color: 'action', + }, + style: { + color: (theme.vars || theme).palette.action.active, + }, + }, + { + props: { + color: 'disabled', + }, + style: { + color: (theme.vars || theme).palette.action.disabled, + }, + }, + { + props: { + color: 'inherit', + }, + style: { + color: undefined, + }, + }, + ...Object.entries(theme.palette) + .filter(([, palette]) => palette.main) + .map(([color]) => ({ + props: { color }, + style: { + color: (theme.vars || theme).palette[color].main, + }, + })), + ], })); const Icon = React.forwardRef(function Icon(inProps, ref) { @@ -170,6 +219,8 @@ Icon.propTypes /* remove-proptypes */ = { ]), }; -Icon.muiName = 'Icon'; +if (Icon) { + Icon.muiName = 'Icon'; +} export default Icon; diff --git a/packages/mui-material/src/ImageList/ImageList.js b/packages/mui-material/src/ImageList/ImageList.js index 1bb5af39974eee..5eddd5b2d0e93c 100644 --- a/packages/mui-material/src/ImageList/ImageList.js +++ b/packages/mui-material/src/ImageList/ImageList.js @@ -4,11 +4,12 @@ import integerPropType from '@mui/utils/integerPropType'; import clsx from 'clsx'; import PropTypes from 'prop-types'; import * as React from 'react'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getImageListUtilityClass } from './imageListClasses'; import ImageListContext from './ImageListContext'; +const useThemeProps = createUseThemeProps('MuiImageList'); + const useUtilityClasses = (ownerState) => { const { classes, variant } = ownerState; diff --git a/packages/mui-material/src/ImageListItem/ImageListItem.js b/packages/mui-material/src/ImageListItem/ImageListItem.js index 32d2472c1f14e2..db5a43ced0b559 100644 --- a/packages/mui-material/src/ImageListItem/ImageListItem.js +++ b/packages/mui-material/src/ImageListItem/ImageListItem.js @@ -6,11 +6,12 @@ import PropTypes from 'prop-types'; import * as React from 'react'; import { isFragment } from 'react-is'; import ImageListContext from '../ImageList/ImageListContext'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import isMuiElement from '../utils/isMuiElement'; import imageListItemClasses, { getImageListItemUtilityClass } from './imageListItemClasses'; +const useThemeProps = createUseThemeProps('MuiImageListItem'); + const useUtilityClasses = (ownerState) => { const { classes, variant } = ownerState; diff --git a/packages/mui-material/src/ImageListItemBar/ImageListItemBar.js b/packages/mui-material/src/ImageListItemBar/ImageListItemBar.js index 4ec1ae66ce7fe2..f5be968bc2a616 100644 --- a/packages/mui-material/src/ImageListItemBar/ImageListItemBar.js +++ b/packages/mui-material/src/ImageListItemBar/ImageListItemBar.js @@ -3,11 +3,12 @@ import composeClasses from '@mui/utils/composeClasses'; import clsx from 'clsx'; import PropTypes from 'prop-types'; import * as React from 'react'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import capitalize from '../utils/capitalize'; import { getImageListItemBarUtilityClass } from './imageListItemBarClasses'; +const useThemeProps = createUseThemeProps('MuiImageListItemBar'); + const useUtilityClasses = (ownerState) => { const { classes, position, actionIcon, actionPosition } = ownerState; diff --git a/packages/mui-material/src/Input/Input.d.ts b/packages/mui-material/src/Input/Input.d.ts index 39f4b45fb9d8eb..87e624d32c0b21 100644 --- a/packages/mui-material/src/Input/Input.d.ts +++ b/packages/mui-material/src/Input/Input.d.ts @@ -10,6 +10,7 @@ export interface InputProps extends StandardProps { classes?: Partial; /** * If `true`, the `input` will not have an underline. + * @default false */ disableUnderline?: boolean; /** diff --git a/packages/mui-material/src/Input/Input.js b/packages/mui-material/src/Input/Input.js index 23f0d477ed74f3..e674c0c583c89b 100644 --- a/packages/mui-material/src/Input/Input.js +++ b/packages/mui-material/src/Input/Input.js @@ -5,16 +5,18 @@ import composeClasses from '@mui/utils/composeClasses'; import deepmerge from '@mui/utils/deepmerge'; import refType from '@mui/utils/refType'; import InputBase from '../InputBase'; -import styled, { rootShouldForwardProp } from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; +import { styled, createUseThemeProps } from '../zero-styled'; import inputClasses, { getInputUtilityClass } from './inputClasses'; import { rootOverridesResolver as inputBaseRootOverridesResolver, inputOverridesResolver as inputBaseInputOverridesResolver, InputBaseRoot, - InputBaseComponent as InputBaseInput, + InputBaseInput, } from '../InputBase/InputBase'; +const useThemeProps = createUseThemeProps('MuiInput'); + const useUtilityClasses = (ownerState) => { const { classes, disableUnderline } = ownerState; @@ -43,7 +45,7 @@ const InputRoot = styled(InputBaseRoot, { !ownerState.disableUnderline && styles.underline, ]; }, -})(({ theme, ownerState }) => { +})(({ theme }) => { const light = theme.palette.mode === 'light'; let bottomLineColor = light ? 'rgba(0, 0, 0, 0.42)' : 'rgba(255, 255, 255, 0.7)'; if (theme.vars) { @@ -51,61 +53,78 @@ const InputRoot = styled(InputBaseRoot, { } return { position: 'relative', - ...(ownerState.formControl && { - 'label + &': { - marginTop: 16, - }, - }), - ...(!ownerState.disableUnderline && { - '&::after': { - borderBottom: `2px solid ${(theme.vars || theme).palette[ownerState.color].main}`, - left: 0, - bottom: 0, - // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242 - content: '""', - position: 'absolute', - right: 0, - transform: 'scaleX(0)', - transition: theme.transitions.create('transform', { - duration: theme.transitions.duration.shorter, - easing: theme.transitions.easing.easeOut, - }), - pointerEvents: 'none', // Transparent to the hover style. - }, - [`&.${inputClasses.focused}:after`]: { - // translateX(0) is a workaround for Safari transform scale bug - // See https://github.com/mui/material-ui/issues/31766 - transform: 'scaleX(1) translateX(0)', - }, - [`&.${inputClasses.error}`]: { - '&::before, &::after': { - borderBottomColor: (theme.vars || theme).palette.error.main, + variants: [ + { + props: ({ ownerState }) => ownerState.formControl, + style: { + 'label + &': { + marginTop: 16, + }, }, }, - '&::before': { - borderBottom: `1px solid ${bottomLineColor}`, - left: 0, - bottom: 0, - // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242 - content: '"\\00a0"', - position: 'absolute', - right: 0, - transition: theme.transitions.create('border-bottom-color', { - duration: theme.transitions.duration.shorter, - }), - pointerEvents: 'none', // Transparent to the hover style. - }, - [`&:hover:not(.${inputClasses.disabled}, .${inputClasses.error}):before`]: { - borderBottom: `2px solid ${(theme.vars || theme).palette.text.primary}`, - // Reset on touch devices, it doesn't add specificity - '@media (hover: none)': { - borderBottom: `1px solid ${bottomLineColor}`, + { + props: ({ ownerState }) => !ownerState.disableUnderline, + style: { + '&::after': { + left: 0, + bottom: 0, + // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242 + content: '""', + position: 'absolute', + right: 0, + transform: 'scaleX(0)', + transition: theme.transitions.create('transform', { + duration: theme.transitions.duration.shorter, + easing: theme.transitions.easing.easeOut, + }), + pointerEvents: 'none', // Transparent to the hover style. + }, + [`&.${inputClasses.focused}:after`]: { + // translateX(0) is a workaround for Safari transform scale bug + // See https://github.com/mui/material-ui/issues/31766 + transform: 'scaleX(1) translateX(0)', + }, + [`&.${inputClasses.error}`]: { + '&::before, &::after': { + borderBottomColor: (theme.vars || theme).palette.error.main, + }, + }, + '&::before': { + borderBottom: `1px solid ${bottomLineColor}`, + left: 0, + bottom: 0, + // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242 + content: '"\\00a0"', + position: 'absolute', + right: 0, + transition: theme.transitions.create('border-bottom-color', { + duration: theme.transitions.duration.shorter, + }), + pointerEvents: 'none', // Transparent to the hover style. + }, + [`&:hover:not(.${inputClasses.disabled}, .${inputClasses.error}):before`]: { + borderBottom: `2px solid ${(theme.vars || theme).palette.text.primary}`, + // Reset on touch devices, it doesn't add specificity + '@media (hover: none)': { + borderBottom: `1px solid ${bottomLineColor}`, + }, + }, + [`&.${inputClasses.disabled}:before`]: { + borderBottomStyle: 'dotted', + }, }, }, - [`&.${inputClasses.disabled}:before`]: { - borderBottomStyle: 'dotted', - }, - }), + ...Object.entries(theme.palette) + .filter(([, value]) => value.main) + .map(([color]) => ({ + props: { color, disableUnderline: false }, + style: { + '&::after': { + borderBottom: `2px solid ${(theme.vars || theme).palette[color].main}`, + }, + }, + })), + ], }; }); @@ -118,7 +137,7 @@ const InputInput = styled(InputBaseInput, { const Input = React.forwardRef(function Input(inProps, ref) { const props = useThemeProps({ props: inProps, name: 'MuiInput' }); const { - disableUnderline, + disableUnderline = false, components = {}, componentsProps: componentsPropsProp, fullWidth = false, @@ -223,6 +242,7 @@ Input.propTypes /* remove-proptypes */ = { disabled: PropTypes.bool, /** * If `true`, the `input` will not have an underline. + * @default false */ disableUnderline: PropTypes.bool, /** @@ -352,6 +372,8 @@ Input.propTypes /* remove-proptypes */ = { value: PropTypes.any, }; -Input.muiName = 'Input'; +if (Input) { + Input.muiName = 'Input'; +} export default Input; diff --git a/packages/mui-material/src/InputAdornment/InputAdornment.js b/packages/mui-material/src/InputAdornment/InputAdornment.js index 286d7f3463c249..4ce2c503162b96 100644 --- a/packages/mui-material/src/InputAdornment/InputAdornment.js +++ b/packages/mui-material/src/InputAdornment/InputAdornment.js @@ -7,9 +7,10 @@ import capitalize from '../utils/capitalize'; import Typography from '../Typography'; import FormControlContext from '../FormControl/FormControlContext'; import useFormControl from '../FormControl/useFormControl'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import inputAdornmentClasses, { getInputAdornmentUtilityClass } from './inputAdornmentClasses'; -import useThemeProps from '../styles/useThemeProps'; + +const useThemeProps = createUseThemeProps('MuiInputAdornment'); const overridesResolver = (props, styles) => { const { ownerState } = props; @@ -42,31 +43,49 @@ const InputAdornmentRoot = styled('div', { name: 'MuiInputAdornment', slot: 'Root', overridesResolver, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ display: 'flex', height: '0.01em', // Fix IE11 flexbox alignment. To remove at some point. maxHeight: '2em', alignItems: 'center', whiteSpace: 'nowrap', color: (theme.vars || theme).palette.action.active, - ...(ownerState.variant === 'filled' && { - // Styles applied to the root element if `variant="filled"`. - [`&.${inputAdornmentClasses.positionStart}&:not(.${inputAdornmentClasses.hiddenLabel})`]: { - marginTop: 16, + variants: [ + { + props: { + variant: 'filled', + }, + style: { + [`&.${inputAdornmentClasses.positionStart}&:not(.${inputAdornmentClasses.hiddenLabel})`]: { + marginTop: 16, + }, + }, + }, + { + props: { + position: 'start', + }, + style: { + marginRight: 8, + }, + }, + { + props: { + position: 'end', + }, + style: { + marginLeft: 8, + }, + }, + { + props: { + disablePointerEvents: true, + }, + style: { + pointerEvents: 'none', + }, }, - }), - ...(ownerState.position === 'start' && { - // Styles applied to the root element if `position="start"`. - marginRight: 8, - }), - ...(ownerState.position === 'end' && { - // Styles applied to the root element if `position="end"`. - marginLeft: 8, - }), - ...(ownerState.disablePointerEvents === true && { - // Styles applied to the root element if `disablePointerEvents={true}`. - pointerEvents: 'none', - }), + ], })); const InputAdornment = React.forwardRef(function InputAdornment(inProps, ref) { diff --git a/packages/mui-material/src/InputBase/InputBase.js b/packages/mui-material/src/InputBase/InputBase.js index 970dd62ab36b2c..3be8ca90edafc8 100644 --- a/packages/mui-material/src/InputBase/InputBase.js +++ b/packages/mui-material/src/InputBase/InputBase.js @@ -11,8 +11,7 @@ import composeClasses from '@mui/utils/composeClasses'; import formControlState from '../FormControl/formControlState'; import FormControlContext from '../FormControl/FormControlContext'; import useFormControl from '../FormControl/useFormControl'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import capitalize from '../utils/capitalize'; import useForkRef from '../utils/useForkRef'; import useEnhancedEffect from '../utils/useEnhancedEffect'; @@ -20,6 +19,8 @@ import GlobalStyles from '../GlobalStyles'; import { isFilled } from './utils'; import inputBaseClasses, { getInputBaseUtilityClass } from './inputBaseClasses'; +const useThemeProps = createUseThemeProps('MuiInputBase'); + export const rootOverridesResolver = (props, styles) => { const { ownerState } = props; @@ -104,7 +105,7 @@ export const InputBaseRoot = styled('div', { name: 'MuiInputBase', slot: 'Root', overridesResolver: rootOverridesResolver, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ ...theme.typography.body1, color: (theme.vars || theme).palette.text.primary, lineHeight: '1.4375em', // 23px @@ -117,22 +118,33 @@ export const InputBaseRoot = styled('div', { color: (theme.vars || theme).palette.text.disabled, cursor: 'default', }, - ...(ownerState.multiline && { - padding: '4px 0 5px', - ...(ownerState.size === 'small' && { - paddingTop: 1, - }), - }), - ...(ownerState.fullWidth && { - width: '100%', - }), + variants: [ + { + props: ({ ownerState }) => ownerState.multiline, + style: { + padding: '4px 0 5px', + }, + }, + { + props: ({ ownerState, size }) => ownerState.multiline && size === 'small', + style: { + paddingTop: 1, + }, + }, + { + props: ({ ownerState }) => ownerState.fullWidth, + style: { + width: '100%', + }, + }, + ], })); -export const InputBaseComponent = styled('input', { +export const InputBaseInput = styled('input', { name: 'MuiInputBase', slot: 'Input', overridesResolver: inputOverridesResolver, -})(({ theme, ownerState }) => { +})(({ theme }) => { const light = theme.palette.mode === 'light'; const placeholder = { color: 'currentColor', @@ -147,11 +159,9 @@ export const InputBaseComponent = styled('input', { duration: theme.transitions.duration.shorter, }), }; - const placeholderHidden = { opacity: '0 !important', }; - const placeholderVisible = theme.vars ? { opacity: theme.vars.opacity.inputPlaceholder, @@ -211,19 +221,33 @@ export const InputBaseComponent = styled('input', { animationDuration: '5000s', animationName: 'mui-auto-fill', }, - ...(ownerState.size === 'small' && { - paddingTop: 1, - }), - ...(ownerState.multiline && { - height: 'auto', - resize: 'none', - padding: 0, - paddingTop: 0, - }), - ...(ownerState.type === 'search' && { - // Improve type search style. - MozAppearance: 'textfield', - }), + variants: [ + { + props: { + size: 'small', + }, + style: { + paddingTop: 1, + }, + }, + { + props: ({ ownerState }) => ownerState.multiline, + style: { + height: 'auto', + resize: 'none', + padding: 0, + paddingTop: 0, + }, + }, + { + props: { + type: 'search', + }, + style: { + MozAppearance: 'textfield', // Improve type search style. + }, + }, + ], }; }); @@ -506,7 +530,7 @@ const InputBase = React.forwardRef(function InputBase(inProps, ref) { const Root = slots.root || components.Root || InputBaseRoot; const rootProps = slotProps.root || componentsProps.root || {}; - const Input = slots.input || components.Input || InputBaseComponent; + const Input = slots.input || components.Input || InputBaseInput; inputProps = { ...inputProps, ...(slotProps.input ?? componentsProps.input) }; return ( diff --git a/packages/mui-material/src/InputLabel/InputLabel.js b/packages/mui-material/src/InputLabel/InputLabel.js index dd8003ee8ebb7c..b47991c21fa676 100644 --- a/packages/mui-material/src/InputLabel/InputLabel.js +++ b/packages/mui-material/src/InputLabel/InputLabel.js @@ -6,11 +6,13 @@ import clsx from 'clsx'; import formControlState from '../FormControl/formControlState'; import useFormControl from '../FormControl/useFormControl'; import FormLabel, { formLabelClasses } from '../FormLabel'; -import useThemeProps from '../styles/useThemeProps'; import capitalize from '../utils/capitalize'; -import styled, { rootShouldForwardProp } from '../styles/styled'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getInputLabelUtilityClasses } from './inputLabelClasses'; +const useThemeProps = createUseThemeProps('MuiInputLabel'); + const useUtilityClasses = (ownerState) => { const { classes, formControl, size, shrink, disableAnimation, variant, required } = ownerState; const slots = { @@ -50,75 +52,123 @@ const InputLabelRoot = styled(FormLabel, { styles[ownerState.variant], ]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ display: 'block', transformOrigin: 'top left', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: '100%', - ...(ownerState.formControl && { - position: 'absolute', - left: 0, - top: 0, - // slight alteration to spec spacing to match visual spec result - transform: 'translate(0, 20px) scale(1)', - }), - ...(ownerState.size === 'small' && { - // Compensation for the `Input.inputSizeSmall` style. - transform: 'translate(0, 17px) scale(1)', - }), - ...(ownerState.shrink && { - transform: 'translate(0, -1.5px) scale(0.75)', - transformOrigin: 'top left', - maxWidth: '133%', - }), - ...(!ownerState.disableAnimation && { - transition: theme.transitions.create(['color', 'transform', 'max-width'], { - duration: theme.transitions.duration.shorter, - easing: theme.transitions.easing.easeOut, - }), - }), - ...(ownerState.variant === 'filled' && { - // Chrome's autofill feature gives the input field a yellow background. - // Since the input field is behind the label in the HTML tree, - // the input field is drawn last and hides the label with an opaque background color. - // zIndex: 1 will raise the label above opaque background-colors of input. - zIndex: 1, - pointerEvents: 'none', - transform: 'translate(12px, 16px) scale(1)', - maxWidth: 'calc(100% - 24px)', - ...(ownerState.size === 'small' && { - transform: 'translate(12px, 13px) scale(1)', - }), - ...(ownerState.shrink && { - userSelect: 'none', - pointerEvents: 'auto', - transform: 'translate(12px, 7px) scale(0.75)', - maxWidth: 'calc(133% - 24px)', - ...(ownerState.size === 'small' && { + variants: [ + { + props: ({ ownerState }) => ownerState.formControl, + style: { + position: 'absolute', + left: 0, + top: 0, + // slight alteration to spec spacing to match visual spec result + transform: 'translate(0, 20px) scale(1)', + }, + }, + { + props: { + size: 'small', + }, + style: { + // Compensation for the `Input.inputSizeSmall` style. + transform: 'translate(0, 17px) scale(1)', + }, + }, + { + props: ({ ownerState }) => ownerState.shrink, + style: { + transform: 'translate(0, -1.5px) scale(0.75)', + transformOrigin: 'top left', + maxWidth: '133%', + }, + }, + { + props: ({ ownerState }) => !ownerState.disableAnimation, + style: { + transition: theme.transitions.create(['color', 'transform', 'max-width'], { + duration: theme.transitions.duration.shorter, + easing: theme.transitions.easing.easeOut, + }), + }, + }, + { + props: { + variant: 'filled', + }, + style: { + // Chrome's autofill feature gives the input field a yellow background. + // Since the input field is behind the label in the HTML tree, + // the input field is drawn last and hides the label with an opaque background color. + // zIndex: 1 will raise the label above opaque background-colors of input. + zIndex: 1, + pointerEvents: 'none', + transform: 'translate(12px, 16px) scale(1)', + maxWidth: 'calc(100% - 24px)', + }, + }, + { + props: { + variant: 'filled', + size: 'small', + }, + style: { + transform: 'translate(12px, 13px) scale(1)', + }, + }, + { + props: ({ variant, ownerState }) => variant === 'filled' && ownerState.shrink, + style: { + userSelect: 'none', + pointerEvents: 'auto', + transform: 'translate(12px, 7px) scale(0.75)', + maxWidth: 'calc(133% - 24px)', + }, + }, + { + props: ({ variant, ownerState, size }) => + variant === 'filled' && ownerState.shrink && size === 'small', + style: { transform: 'translate(12px, 4px) scale(0.75)', - }), - }), - }), - ...(ownerState.variant === 'outlined' && { - // see comment above on filled.zIndex - zIndex: 1, - pointerEvents: 'none', - transform: 'translate(14px, 16px) scale(1)', - maxWidth: 'calc(100% - 24px)', - ...(ownerState.size === 'small' && { - transform: 'translate(14px, 9px) scale(1)', - }), - ...(ownerState.shrink && { - userSelect: 'none', - pointerEvents: 'auto', - // Theoretically, we should have (8+5)*2/0.75 = 34px - // but it feels a better when it bleeds a bit on the left, so 32px. - maxWidth: 'calc(133% - 32px)', - transform: 'translate(14px, -9px) scale(0.75)', - }), - }), + }, + }, + { + props: { + variant: 'outlined', + }, + style: { + // see comment above on filled.zIndex + zIndex: 1, + pointerEvents: 'none', + transform: 'translate(14px, 16px) scale(1)', + maxWidth: 'calc(100% - 24px)', + }, + }, + { + props: { + variant: 'outlined', + size: 'small', + }, + style: { + transform: 'translate(14px, 9px) scale(1)', + }, + }, + { + props: ({ variant, ownerState }) => variant === 'outlined' && ownerState.shrink, + style: { + userSelect: 'none', + pointerEvents: 'auto', + // Theoretically, we should have (8+5)*2/0.75 = 34px + // but it feels a better when it bleeds a bit on the left, so 32px. + maxWidth: 'calc(133% - 32px)', + transform: 'translate(14px, -9px) scale(0.75)', + }, + }, + ], })); const InputLabel = React.forwardRef(function InputLabel(inProps, ref) { diff --git a/packages/mui-material/src/Link/Link.js b/packages/mui-material/src/Link/Link.js index f5e72605b7312d..489d82c23d2332 100644 --- a/packages/mui-material/src/Link/Link.js +++ b/packages/mui-material/src/Link/Link.js @@ -2,16 +2,19 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; +import { alpha } from '@mui/system/colorManipulator'; import elementTypeAcceptingRef from '@mui/utils/elementTypeAcceptingRef'; import composeClasses from '@mui/utils/composeClasses'; import capitalize from '../utils/capitalize'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import useIsFocusVisible from '../utils/useIsFocusVisible'; import useForkRef from '../utils/useForkRef'; import Typography from '../Typography'; import linkClasses, { getLinkUtilityClass } from './linkClasses'; import getTextDecoration, { colorTransformations } from './getTextDecoration'; +import useTheme from '../styles/useTheme'; + +const useThemeProps = createUseThemeProps('MuiLink'); const useUtilityClasses = (ownerState) => { const { classes, component, focusVisible, underline } = ownerState; @@ -40,49 +43,84 @@ const LinkRoot = styled(Typography, { ownerState.component === 'button' && styles.button, ]; }, -})(({ theme, ownerState }) => { +})(({ theme }) => { return { - ...(ownerState.underline === 'none' && { - textDecoration: 'none', - }), - ...(ownerState.underline === 'hover' && { - textDecoration: 'none', - '&:hover': { - textDecoration: 'underline', + variants: [ + { + props: { + underline: 'none', + }, + style: { + textDecoration: 'none', + }, + }, + { + props: { + underline: 'hover', + }, + style: { + textDecoration: 'none', + '&:hover': { + textDecoration: 'underline', + }, + }, }, - }), - ...(ownerState.underline === 'always' && { - textDecoration: 'underline', - ...(ownerState.color !== 'inherit' && { - textDecorationColor: getTextDecoration({ theme, ownerState }), - }), - '&:hover': { - textDecorationColor: 'inherit', + { + props: { + underline: 'always', + }, + style: { + textDecoration: 'underline', + '&:hover': { + textDecorationColor: 'inherit', + }, + }, }, - }), - // Same reset as ButtonBase.root - ...(ownerState.component === 'button' && { - position: 'relative', - WebkitTapHighlightColor: 'transparent', - backgroundColor: 'transparent', // Reset default value - // We disable the focus ring for mouse, touch and keyboard users. - outline: 0, - border: 0, - margin: 0, // Remove the margin in Safari - borderRadius: 0, - padding: 0, // Remove the padding in Firefox - cursor: 'pointer', - userSelect: 'none', - verticalAlign: 'middle', - MozAppearance: 'none', // Reset - WebkitAppearance: 'none', // Reset - '&::-moz-focus-inner': { - borderStyle: 'none', // Remove Firefox dotted outline. + { + props: ({ underline, ownerState }) => + underline === 'always' && ownerState.color !== 'inherit', + style: { + textDecorationColor: 'var(--Link-underlineColor)', + }, }, - [`&.${linkClasses.focusVisible}`]: { - outline: 'auto', + ...Object.entries(theme.palette) + .filter(([, value]) => value.main) + .map(([color]) => ({ + props: { underline: 'always', color }, + style: { + '--Link-underlineColor': theme.vars + ? `rgba(${theme.vars.palette[color].mainChannel} / 0.4)` + : alpha(theme.palette[color].main, 0.4), + }, + })), + { + props: { + component: 'button', + }, + style: { + position: 'relative', + WebkitTapHighlightColor: 'transparent', + backgroundColor: 'transparent', // Reset default value + // We disable the focus ring for mouse, touch and keyboard users. + outline: 0, + border: 0, + margin: 0, // Remove the margin in Safari + borderRadius: 0, + padding: 0, // Remove the padding in Firefox + cursor: 'pointer', + userSelect: 'none', + verticalAlign: 'middle', + MozAppearance: 'none', // Reset + WebkitAppearance: 'none', // Reset + '&::-moz-focus-inner': { + borderStyle: 'none', // Remove Firefox dotted outline. + }, + [`&.${linkClasses.focusVisible}`]: { + outline: 'auto', + }, + }, }, - }), + ], }; }); @@ -91,6 +129,7 @@ const Link = React.forwardRef(function Link(inProps, ref) { props: inProps, name: 'MuiLink', }); + const theme = useTheme(); const { className, @@ -154,11 +193,18 @@ const Link = React.forwardRef(function Link(inProps, ref) { ref={handlerRef} ownerState={ownerState} variant={variant} + {...other} sx={[ - ...(!Object.keys(colorTransformations).includes(color) ? [{ color }] : []), + ...(colorTransformations[color] === undefined ? [{ color }] : []), ...(Array.isArray(sx) ? sx : [sx]), ]} - {...other} + style={{ + ...other.style, + ...(underline === 'always' && + color !== 'inherit' && { + '--Link-underlineColor': getTextDecoration({ theme, ownerState }), + }), + }} /> ); }); @@ -198,6 +244,10 @@ Link.propTypes /* remove-proptypes */ = { * @ignore */ onFocus: PropTypes.func, + /** + * @ignore + */ + style: PropTypes.object, /** * The system prop that allows defining system overrides as well as additional CSS styles. */ diff --git a/packages/mui-material/src/Link/getTextDecoration.test.js b/packages/mui-material/src/Link/getTextDecoration.test.js index 803567fc94fd7b..41e92011448c54 100644 --- a/packages/mui-material/src/Link/getTextDecoration.test.js +++ b/packages/mui-material/src/Link/getTextDecoration.test.js @@ -7,21 +7,18 @@ describe('getTextDecoration', () => { const theme = createTheme(); it('deprecated color', () => { - expect(getTextDecoration({ theme, ownerState: { color: 'primary' } })).to.equal( - 'rgba(25, 118, 210, 0.4)', - ); expect(getTextDecoration({ theme, ownerState: { color: 'textPrimary' } })).to.equal( 'rgba(0, 0, 0, 0.4)', ); - expect(getTextDecoration({ theme, ownerState: { color: 'secondary' } })).to.equal( - 'rgba(156, 39, 176, 0.4)', - ); expect(getTextDecoration({ theme, ownerState: { color: 'textSecondary' } })).to.equal( 'rgba(0, 0, 0, 0.4)', ); - expect(getTextDecoration({ theme, ownerState: { color: 'error' } })).to.equal( - 'rgba(211, 47, 47, 0.4)', - ); + expect(getTextDecoration({ theme, ownerState: { color: 'primary' } })).to.equal(null); + expect(getTextDecoration({ theme, ownerState: { color: 'secondary' } })).to.equal(null); + expect(getTextDecoration({ theme, ownerState: { color: 'error' } })).to.equal(null); + expect(getTextDecoration({ theme, ownerState: { color: 'info' } })).to.equal(null); + expect(getTextDecoration({ theme, ownerState: { color: 'success' } })).to.equal(null); + expect(getTextDecoration({ theme, ownerState: { color: 'warning' } })).to.equal(null); }); it('system color', () => { @@ -78,21 +75,18 @@ describe('getTextDecoration', () => { }; // in the application, the value will be CSS variable: `rgba(var(--the-color-channel) / 0.4)` it('deprecated color', () => { - expect(getTextDecoration({ theme, ownerState: { color: 'primary' } })).to.equal( - 'rgba(var(--palette-primary-mainChannel) / 0.4)', - ); expect(getTextDecoration({ theme, ownerState: { color: 'textPrimary' } })).to.equal( 'rgba(var(--palette-text-primaryChannel) / 0.4)', ); - expect(getTextDecoration({ theme, ownerState: { color: 'secondary' } })).to.equal( - 'rgba(var(--palette-secondary-mainChannel) / 0.4)', - ); expect(getTextDecoration({ theme, ownerState: { color: 'textSecondary' } })).to.equal( 'rgba(var(--palette-text-secondaryChannel) / 0.4)', ); - expect(getTextDecoration({ theme, ownerState: { color: 'error' } })).to.equal( - 'rgba(var(--palette-error-mainChannel) / 0.4)', - ); + expect(getTextDecoration({ theme, ownerState: { color: 'primary' } })).to.equal(null); + expect(getTextDecoration({ theme, ownerState: { color: 'secondary' } })).to.equal(null); + expect(getTextDecoration({ theme, ownerState: { color: 'error' } })).to.equal(null); + expect(getTextDecoration({ theme, ownerState: { color: 'info' } })).to.equal(null); + expect(getTextDecoration({ theme, ownerState: { color: 'success' } })).to.equal(null); + expect(getTextDecoration({ theme, ownerState: { color: 'warning' } })).to.equal(null); }); it('system color', () => { diff --git a/packages/mui-material/src/Link/getTextDecoration.ts b/packages/mui-material/src/Link/getTextDecoration.ts index 7cdb42cd9d501f..517d8e77eaab23 100644 --- a/packages/mui-material/src/Link/getTextDecoration.ts +++ b/packages/mui-material/src/Link/getTextDecoration.ts @@ -1,17 +1,18 @@ -import { getPath } from '@mui/system'; +import { getPath } from '@mui/system/style'; import { alpha } from '@mui/system/colorManipulator'; import type { Theme } from '../styles'; -export const colorTransformations = { - primary: 'primary.main', +// TODO v7: remove this transformation +export const colorTransformations: Record = { textPrimary: 'text.primary', - secondary: 'secondary.main', textSecondary: 'text.secondary', - error: 'error.main', -}; - -const transformDeprecatedColors = (color: string) => { - return colorTransformations[color as keyof typeof colorTransformations] || color; + // For main palette, the color will be applied by the styles above. + primary: null, + secondary: null, + error: null, + info: null, + success: null, + warning: null, }; const getTextDecoration = ({ @@ -21,7 +22,13 @@ const getTextDecoration = ({ theme: T; ownerState: { color: string }; }) => { - const transformedColor = transformDeprecatedColors(ownerState.color); + let transformedColor = colorTransformations[ownerState.color]; + if (transformedColor === null) { + return null; + } + if (transformedColor === undefined) { + transformedColor = ownerState.color; + } const color = (getPath(theme, `palette.${transformedColor}`, false) || ownerState.color) as string; const channelColor = getPath(theme, `palette.${transformedColor}Channel`) as string | null; diff --git a/packages/mui-material/src/List/List.js b/packages/mui-material/src/List/List.js index aecb83a331e8ae..d2eda963fdb226 100644 --- a/packages/mui-material/src/List/List.js +++ b/packages/mui-material/src/List/List.js @@ -3,11 +3,12 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import ListContext from './ListContext'; import { getListUtilityClass } from './listClasses'; +const useThemeProps = createUseThemeProps('MuiList'); + const useUtilityClasses = (ownerState) => { const { classes, disablePadding, dense, subheader } = ownerState; @@ -31,19 +32,27 @@ const ListRoot = styled('ul', { ownerState.subheader && styles.subheader, ]; }, -})(({ ownerState }) => ({ +})({ listStyle: 'none', margin: 0, padding: 0, position: 'relative', - ...(!ownerState.disablePadding && { - paddingTop: 8, - paddingBottom: 8, - }), - ...(ownerState.subheader && { - paddingTop: 0, - }), -})); + variants: [ + { + props: ({ ownerState }) => !ownerState.disablePadding, + style: { + paddingTop: 8, + paddingBottom: 8, + }, + }, + { + props: ({ ownerState }) => ownerState.subheader, + style: { + paddingTop: 0, + }, + }, + ], +}); const List = React.forwardRef(function List(inProps, ref) { const props = useThemeProps({ props: inProps, name: 'MuiList' }); diff --git a/packages/mui-material/src/ListItem/ListItem.js b/packages/mui-material/src/ListItem/ListItem.js index 82bc5a8659cbed..afdd2218a9a717 100644 --- a/packages/mui-material/src/ListItem/ListItem.js +++ b/packages/mui-material/src/ListItem/ListItem.js @@ -7,8 +7,7 @@ import composeClasses from '@mui/utils/composeClasses'; import elementTypeAcceptingRef from '@mui/utils/elementTypeAcceptingRef'; import chainPropTypes from '@mui/utils/chainPropTypes'; import { alpha } from '@mui/system/colorManipulator'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import ButtonBase from '../ButtonBase'; import isMuiElement from '../utils/isMuiElement'; import useEnhancedEffect from '../utils/useEnhancedEffect'; @@ -18,6 +17,8 @@ import listItemClasses, { getListItemUtilityClass } from './listItemClasses'; import { listItemButtonClasses } from '../ListItemButton'; import ListItemSecondaryAction from '../ListItemSecondaryAction'; +const useThemeProps = createUseThemeProps('MuiListItem'); + export const overridesResolver = (props, styles) => { const { ownerState } = props; diff --git a/packages/mui-material/src/ListItemAvatar/ListItemAvatar.js b/packages/mui-material/src/ListItemAvatar/ListItemAvatar.js index e076be63c2d5c9..f7138878c93ac7 100644 --- a/packages/mui-material/src/ListItemAvatar/ListItemAvatar.js +++ b/packages/mui-material/src/ListItemAvatar/ListItemAvatar.js @@ -4,10 +4,11 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import ListContext from '../List/ListContext'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getListItemAvatarUtilityClass } from './listItemAvatarClasses'; +const useThemeProps = createUseThemeProps('MuiListItemAvatar'); + const useUtilityClasses = (ownerState) => { const { alignItems, classes } = ownerState; diff --git a/packages/mui-material/src/ListItemButton/ListItemButton.js b/packages/mui-material/src/ListItemButton/ListItemButton.js index f05cadc79adbde..96bcca86416d8e 100644 --- a/packages/mui-material/src/ListItemButton/ListItemButton.js +++ b/packages/mui-material/src/ListItemButton/ListItemButton.js @@ -4,14 +4,16 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import { alpha } from '@mui/system/colorManipulator'; -import styled, { rootShouldForwardProp } from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; import ButtonBase from '../ButtonBase'; import useEnhancedEffect from '../utils/useEnhancedEffect'; import useForkRef from '../utils/useForkRef'; import ListContext from '../List/ListContext'; import listItemButtonClasses, { getListItemButtonUtilityClass } from './listItemButtonClasses'; +const useThemeProps = createUseThemeProps('MuiListItemButton'); + export const overridesResolver = (props, styles) => { const { ownerState } = props; diff --git a/packages/mui-material/src/ListItemIcon/ListItemIcon.js b/packages/mui-material/src/ListItemIcon/ListItemIcon.js index 7a143e3d89d8c0..d3d158aef7b68c 100644 --- a/packages/mui-material/src/ListItemIcon/ListItemIcon.js +++ b/packages/mui-material/src/ListItemIcon/ListItemIcon.js @@ -3,11 +3,12 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getListItemIconUtilityClass } from './listItemIconClasses'; import ListContext from '../List/ListContext'; +const useThemeProps = createUseThemeProps('MuiListItemIcon'); + const useUtilityClasses = (ownerState) => { const { alignItems, classes } = ownerState; @@ -26,14 +27,21 @@ const ListItemIconRoot = styled('div', { return [styles.root, ownerState.alignItems === 'flex-start' && styles.alignItemsFlexStart]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ minWidth: 56, color: (theme.vars || theme).palette.action.active, flexShrink: 0, display: 'inline-flex', - ...(ownerState.alignItems === 'flex-start' && { - marginTop: 8, - }), + variants: [ + { + props: { + alignItems: 'flex-start', + }, + style: { + marginTop: 8, + }, + }, + ], })); /** diff --git a/packages/mui-material/src/ListItemSecondaryAction/ListItemSecondaryAction.js b/packages/mui-material/src/ListItemSecondaryAction/ListItemSecondaryAction.js index f098749fe6d35b..d3e0058fd93e22 100644 --- a/packages/mui-material/src/ListItemSecondaryAction/ListItemSecondaryAction.js +++ b/packages/mui-material/src/ListItemSecondaryAction/ListItemSecondaryAction.js @@ -3,11 +3,12 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import ListContext from '../List/ListContext'; import { getListItemSecondaryActionClassesUtilityClass } from './listItemSecondaryActionClasses'; +const useThemeProps = createUseThemeProps('MuiListItemSecondaryAction'); + const useUtilityClasses = (ownerState) => { const { disableGutters, classes } = ownerState; diff --git a/packages/mui-material/src/ListItemText/ListItemText.js b/packages/mui-material/src/ListItemText/ListItemText.js index 3c6af814ca33fb..0352eecbe62bbf 100644 --- a/packages/mui-material/src/ListItemText/ListItemText.js +++ b/packages/mui-material/src/ListItemText/ListItemText.js @@ -5,10 +5,11 @@ import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import Typography from '../Typography'; import ListContext from '../List/ListContext'; -import useThemeProps from '../styles/useThemeProps'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import listItemTextClasses, { getListItemTextUtilityClass } from './listItemTextClasses'; +const useThemeProps = createUseThemeProps('MuiListItemText'); + const useUtilityClasses = (ownerState) => { const { classes, inset, primary, secondary, dense } = ownerState; diff --git a/packages/mui-material/src/ListSubheader/ListSubheader.js b/packages/mui-material/src/ListSubheader/ListSubheader.js index 3a869a9436baaf..86d530050d3324 100644 --- a/packages/mui-material/src/ListSubheader/ListSubheader.js +++ b/packages/mui-material/src/ListSubheader/ListSubheader.js @@ -3,11 +3,12 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import capitalize from '../utils/capitalize'; import { getListSubheaderUtilityClass } from './listSubheaderClasses'; +const useThemeProps = createUseThemeProps('MuiListSubheader'); + const useUtilityClasses = (ownerState) => { const { classes, color, disableGutters, inset, disableSticky } = ownerState; @@ -122,7 +123,9 @@ const ListSubheader = React.forwardRef(function ListSubheader(inProps, ref) { ); }); -ListSubheader.muiSkipListHighlight = true; +if (ListSubheader) { + ListSubheader.muiSkipListHighlight = true; +} ListSubheader.propTypes /* remove-proptypes */ = { // ┌────────────────────────────── Warning ──────────────────────────────┐ diff --git a/packages/mui-material/src/Menu/Menu.js b/packages/mui-material/src/Menu/Menu.js index 8fb919b0fb70da..edf4fe4f7dec34 100644 --- a/packages/mui-material/src/Menu/Menu.js +++ b/packages/mui-material/src/Menu/Menu.js @@ -9,10 +9,12 @@ import HTMLElementType from '@mui/utils/HTMLElementType'; import { useRtl } from '@mui/system/RtlProvider'; import MenuList from '../MenuList'; import Popover, { PopoverPaper } from '../Popover'; -import styled, { rootShouldForwardProp } from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getMenuUtilityClass } from './menuClasses'; +const useThemeProps = createUseThemeProps('MuiMenu'); + const RTL_ORIGIN = { vertical: 'top', horizontal: 'right', diff --git a/packages/mui-material/src/MenuItem/MenuItem.js b/packages/mui-material/src/MenuItem/MenuItem.js index fde0d2867c1e1f..7819d4e76e073d 100644 --- a/packages/mui-material/src/MenuItem/MenuItem.js +++ b/packages/mui-material/src/MenuItem/MenuItem.js @@ -4,8 +4,8 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import { alpha } from '@mui/system/colorManipulator'; -import styled, { rootShouldForwardProp } from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; +import { styled, createUseThemeProps } from '../zero-styled'; import ListContext from '../List/ListContext'; import ButtonBase from '../ButtonBase'; import useEnhancedEffect from '../utils/useEnhancedEffect'; @@ -15,6 +15,8 @@ import { listItemIconClasses } from '../ListItemIcon'; import { listItemTextClasses } from '../ListItemText'; import menuItemClasses, { getMenuItemUtilityClass } from './menuItemClasses'; +const useThemeProps = createUseThemeProps('MuiMenuItem'); + export const overridesResolver = (props, styles) => { const { ownerState } = props; @@ -52,7 +54,7 @@ const MenuItemRoot = styled(ButtonBase, { name: 'MuiMenuItem', slot: 'Root', overridesResolver, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ ...theme.typography.body1, display: 'flex', justifyContent: 'flex-start', @@ -64,14 +66,6 @@ const MenuItemRoot = styled(ButtonBase, { paddingBottom: 6, boxSizing: 'border-box', whiteSpace: 'nowrap', - ...(!ownerState.disableGutters && { - paddingLeft: 16, - paddingRight: 16, - }), - ...(ownerState.divider && { - borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, - backgroundClip: 'padding-box', - }), '&:hover': { textDecoration: 'none', backgroundColor: (theme.vars || theme).palette.action.hover, @@ -130,20 +124,42 @@ const MenuItemRoot = styled(ButtonBase, { [`& .${listItemIconClasses.root}`]: { minWidth: 36, }, - ...(!ownerState.dense && { - [theme.breakpoints.up('sm')]: { - minHeight: 'auto', + variants: [ + { + props: ({ ownerState }) => !ownerState.disableGutters, + style: { + paddingLeft: 16, + paddingRight: 16, + }, + }, + { + props: ({ ownerState }) => ownerState.divider, + style: { + borderBottom: `1px solid ${(theme.vars || theme).palette.divider}`, + backgroundClip: 'padding-box', + }, + }, + { + props: ({ ownerState }) => !ownerState.dense, + style: { + [theme.breakpoints.up('sm')]: { + minHeight: 'auto', + }, + }, }, - }), - ...(ownerState.dense && { - minHeight: 32, // https://m2.material.io/components/menus#specs > Dense - paddingTop: 4, - paddingBottom: 4, - ...theme.typography.body2, - [`& .${listItemIconClasses.root} svg`]: { - fontSize: '1.25rem', + { + props: ({ ownerState }) => ownerState.dense, + style: { + minHeight: 32, // https://m2.material.io/components/menus#specs > Dense + paddingTop: 4, + paddingBottom: 4, + ...theme.typography.body2, + [`& .${listItemIconClasses.root} svg`]: { + fontSize: '1.25rem', + }, + }, }, - }), + ], })); const MenuItem = React.forwardRef(function MenuItem(inProps, ref) { diff --git a/packages/mui-material/src/NativeSelect/NativeSelectInput.js b/packages/mui-material/src/NativeSelect/NativeSelectInput.js index 042b89dfa4b3af..db1eae0f282dcb 100644 --- a/packages/mui-material/src/NativeSelect/NativeSelectInput.js +++ b/packages/mui-material/src/NativeSelect/NativeSelectInput.js @@ -6,7 +6,8 @@ import refType from '@mui/utils/refType'; import composeClasses from '@mui/utils/composeClasses'; import capitalize from '../utils/capitalize'; import nativeSelectClasses, { getNativeSelectUtilityClasses } from './nativeSelectClasses'; -import styled, { rootShouldForwardProp } from '../styles/styled'; +import { styled } from '../zero-styled'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; const useUtilityClasses = (ownerState) => { const { classes, variant, disabled, multiple, open, error } = ownerState; @@ -19,23 +20,20 @@ const useUtilityClasses = (ownerState) => { return composeClasses(slots, getNativeSelectUtilityClasses, classes); }; -export const nativeSelectSelectStyles = ({ ownerState, theme }) => ({ - MozAppearance: 'none', // Reset - WebkitAppearance: 'none', // Reset +export const StyledSelectSelect = styled('select')(({ theme }) => ({ + // Reset + MozAppearance: 'none', + // Reset + WebkitAppearance: 'none', // When interacting quickly, the text can end up selected. // Native select can't be selected either. userSelect: 'none', - borderRadius: 0, // Reset + // Reset + borderRadius: 0, cursor: 'pointer', '&:focus': { - // Show that it's not an text input - ...(theme.vars - ? { backgroundColor: `rgba(${theme.vars.palette.common.onBackgroundChannel} / 0.05)` } - : { - backgroundColor: - theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.05)' : 'rgba(255, 255, 255, 0.05)', - }), - borderRadius: 0, // Reset Chrome style + // Reset Chrome style + borderRadius: 0, }, // Remove IE11 arrow '&::-ms-expand': { @@ -50,28 +48,46 @@ export const nativeSelectSelectStyles = ({ ownerState, theme }) => ({ '&:not([multiple]) option, &:not([multiple]) optgroup': { backgroundColor: (theme.vars || theme).palette.background.paper, }, - // Bump specificity to allow extending custom inputs - '&&&': { - paddingRight: 24, - minWidth: 16, // So it doesn't collapse. - }, - ...(ownerState.variant === 'filled' && { - '&&&': { - paddingRight: 32, + variants: [ + { + props: ({ ownerState }) => + ownerState.variant !== 'filled' && ownerState.variant !== 'outlined', + style: { + // Bump specificity to allow extending custom inputs + '&&&': { + paddingRight: 24, + minWidth: 16, // So it doesn't collapse. + }, + }, }, - }), - ...(ownerState.variant === 'outlined' && { - borderRadius: (theme.vars || theme).shape.borderRadius, - '&:focus': { - borderRadius: (theme.vars || theme).shape.borderRadius, // Reset the reset for Chrome style + { + props: { + variant: 'filled', + }, + style: { + '&&&': { + paddingRight: 32, + }, + }, }, - '&&&': { - paddingRight: 32, + { + props: { + variant: 'outlined', + }, + style: { + borderRadius: (theme.vars || theme).shape.borderRadius, + '&:focus': { + borderRadius: (theme.vars || theme).shape.borderRadius, // Reset the reset for Chrome style + }, + '&&&': { + paddingRight: 32, + }, + }, }, - }), -}); + ], +})); -const NativeSelectSelect = styled('select', { +const NativeSelectSelect = styled(StyledSelectSelect, { name: 'MuiNativeSelect', slot: 'Select', shouldForwardProp: rootShouldForwardProp, @@ -85,31 +101,48 @@ const NativeSelectSelect = styled('select', { { [`&.${nativeSelectClasses.multiple}`]: styles.multiple }, ]; }, -})(nativeSelectSelectStyles); +})({}); -export const nativeSelectIconStyles = ({ ownerState, theme }) => ({ +export const StyledSelectIcon = styled('svg')(({ theme }) => ({ // We use a position absolute over a flexbox in order to forward the pointer events // to the input and to support wrapping tags.. position: 'absolute', right: 0, - top: 'calc(50% - .5em)', // Center vertically, height is 1em - pointerEvents: 'none', // Don't block pointer events on the select under the icon. + // Center vertically, height is 1em + top: 'calc(50% - .5em)', + // Don't block pointer events on the select under the icon. + pointerEvents: 'none', color: (theme.vars || theme).palette.action.active, [`&.${nativeSelectClasses.disabled}`]: { color: (theme.vars || theme).palette.action.disabled, }, - ...(ownerState.open && { - transform: 'rotate(180deg)', - }), - ...(ownerState.variant === 'filled' && { - right: 7, - }), - ...(ownerState.variant === 'outlined' && { - right: 7, - }), -}); + variants: [ + { + props: ({ ownerState }) => ownerState.open, + style: { + transform: 'rotate(180deg)', + }, + }, + { + props: { + variant: 'filled', + }, + style: { + right: 7, + }, + }, + { + props: { + variant: 'outlined', + }, + style: { + right: 7, + }, + }, + ], +})); -const NativeSelectIcon = styled('svg', { +const NativeSelectIcon = styled(StyledSelectIcon, { name: 'MuiNativeSelect', slot: 'Icon', overridesResolver: (props, styles) => { @@ -120,7 +153,7 @@ const NativeSelectIcon = styled('svg', { ownerState.open && styles.iconOpen, ]; }, -})(nativeSelectIconStyles); +})({}); /** * @ignore - internal component. diff --git a/packages/mui-material/src/OutlinedInput/NotchedOutline.js b/packages/mui-material/src/OutlinedInput/NotchedOutline.js index 58223da4479c8e..46bf41738ea632 100644 --- a/packages/mui-material/src/OutlinedInput/NotchedOutline.js +++ b/packages/mui-material/src/OutlinedInput/NotchedOutline.js @@ -1,7 +1,8 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import styled, { rootShouldForwardProp } from '../styles/styled'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; +import { styled } from '../zero-styled'; const NotchedOutlineRoot = styled('fieldset', { shouldForwardProp: rootShouldForwardProp })({ textAlign: 'left', @@ -21,46 +22,57 @@ const NotchedOutlineRoot = styled('fieldset', { shouldForwardProp: rootShouldFor }); const NotchedOutlineLegend = styled('legend', { shouldForwardProp: rootShouldForwardProp })( - ({ ownerState, theme }) => ({ + ({ theme }) => ({ float: 'unset', // Fix conflict with bootstrap width: 'auto', // Fix conflict with bootstrap overflow: 'hidden', // Fix Horizontal scroll when label too long - ...(!ownerState.withLabel && { - padding: 0, - lineHeight: '11px', // sync with `height` in `legend` styles - transition: theme.transitions.create('width', { - duration: 150, - easing: theme.transitions.easing.easeOut, - }), - }), - ...(ownerState.withLabel && { - display: 'block', // Fix conflict with normalize.css and sanitize.css - padding: 0, - height: 11, // sync with `lineHeight` in `legend` styles - fontSize: '0.75em', - visibility: 'hidden', - maxWidth: 0.01, - transition: theme.transitions.create('max-width', { - duration: 50, - easing: theme.transitions.easing.easeOut, - }), - whiteSpace: 'nowrap', - '& > span': { - paddingLeft: 5, - paddingRight: 5, - display: 'inline-block', - opacity: 0, - visibility: 'visible', + variants: [ + { + props: ({ ownerState }) => !ownerState.withLabel, + style: { + padding: 0, + lineHeight: '11px', // sync with `height` in `legend` styles + transition: theme.transitions.create('width', { + duration: 150, + easing: theme.transitions.easing.easeOut, + }), + }, }, - ...(ownerState.notched && { - maxWidth: '100%', - transition: theme.transitions.create('max-width', { - duration: 100, - easing: theme.transitions.easing.easeOut, - delay: 50, - }), - }), - }), + { + props: ({ ownerState }) => ownerState.withLabel, + style: { + display: 'block', // Fix conflict with normalize.css and sanitize.css + padding: 0, + height: 11, // sync with `lineHeight` in `legend` styles + fontSize: '0.75em', + visibility: 'hidden', + maxWidth: 0.01, + transition: theme.transitions.create('max-width', { + duration: 50, + easing: theme.transitions.easing.easeOut, + }), + whiteSpace: 'nowrap', + '& > span': { + paddingLeft: 5, + paddingRight: 5, + display: 'inline-block', + opacity: 0, + visibility: 'visible', + }, + }, + }, + { + props: ({ ownerState }) => ownerState.withLabel && ownerState.notched, + style: { + maxWidth: '100%', + transition: theme.transitions.create('max-width', { + duration: 100, + easing: theme.transitions.easing.easeOut, + delay: 50, + }), + }, + }, + ], }), ); @@ -90,7 +102,7 @@ export default function NotchedOutline(props) { ); } -NotchedOutline.propTypes = { +NotchedOutline.propTypes /* remove-proptypes */ = { /** * The content of the component. */ diff --git a/packages/mui-material/src/OutlinedInput/OutlinedInput.js b/packages/mui-material/src/OutlinedInput/OutlinedInput.js index 6d75411fa65732..31242bf1393ea3 100644 --- a/packages/mui-material/src/OutlinedInput/OutlinedInput.js +++ b/packages/mui-material/src/OutlinedInput/OutlinedInput.js @@ -6,15 +6,17 @@ import composeClasses from '@mui/utils/composeClasses'; import NotchedOutline from './NotchedOutline'; import useFormControl from '../FormControl/useFormControl'; import formControlState from '../FormControl/formControlState'; -import styled, { rootShouldForwardProp } from '../styles/styled'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; +import { styled, createUseThemeProps } from '../zero-styled'; import outlinedInputClasses, { getOutlinedInputUtilityClass } from './outlinedInputClasses'; import InputBase, { rootOverridesResolver as inputBaseRootOverridesResolver, inputOverridesResolver as inputBaseInputOverridesResolver, InputBaseRoot, - InputBaseComponent as InputBaseInput, + InputBaseInput, } from '../InputBase/InputBase'; -import useThemeProps from '../styles/useThemeProps'; + +const useThemeProps = createUseThemeProps('MuiOutlinedInput'); const useUtilityClasses = (ownerState) => { const { classes } = ownerState; @@ -38,7 +40,7 @@ const OutlinedInputRoot = styled(InputBaseRoot, { name: 'MuiOutlinedInput', slot: 'Root', overridesResolver: inputBaseRootOverridesResolver, -})(({ theme, ownerState }) => { +})(({ theme }) => { const borderColor = theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)'; return { @@ -47,36 +49,64 @@ const OutlinedInputRoot = styled(InputBaseRoot, { [`&:hover .${outlinedInputClasses.notchedOutline}`]: { borderColor: (theme.vars || theme).palette.text.primary, }, - // Reset on touch devices, it doesn't add specificity - '@media (hover: none)': { - [`&:hover .${outlinedInputClasses.notchedOutline}`]: { - borderColor: theme.vars - ? `rgba(${theme.vars.palette.common.onBackgroundChannel} / 0.23)` - : borderColor, - }, - }, [`&.${outlinedInputClasses.focused} .${outlinedInputClasses.notchedOutline}`]: { - borderColor: (theme.vars || theme).palette[ownerState.color].main, borderWidth: 2, }, - [`&.${outlinedInputClasses.error} .${outlinedInputClasses.notchedOutline}`]: { - borderColor: (theme.vars || theme).palette.error.main, - }, - [`&.${outlinedInputClasses.disabled} .${outlinedInputClasses.notchedOutline}`]: { - borderColor: (theme.vars || theme).palette.action.disabled, - }, - ...(ownerState.startAdornment && { - paddingLeft: 14, - }), - ...(ownerState.endAdornment && { - paddingRight: 14, - }), - ...(ownerState.multiline && { - padding: '16.5px 14px', - ...(ownerState.size === 'small' && { - padding: '8.5px 14px', - }), - }), + variants: [ + ...Object.entries(theme.palette) + .filter(([, value]) => value.main) + .map(([color]) => ({ + props: { color }, + style: { + [`&.${outlinedInputClasses.focused} .${outlinedInputClasses.notchedOutline}`]: { + borderColor: (theme.vars || theme).palette[color].main, + }, + }, + })), + { + props: {}, // to overide the above style + style: { + // Reset on touch devices, it doesn't add specificity + '@media (hover: none)': { + [`&:hover .${outlinedInputClasses.notchedOutline}`]: { + borderColor: theme.vars + ? `rgba(${theme.vars.palette.common.onBackgroundChannel} / 0.23)` + : borderColor, + }, + }, + [`&.${outlinedInputClasses.error} .${outlinedInputClasses.notchedOutline}`]: { + borderColor: (theme.vars || theme).palette.error.main, + }, + [`&.${outlinedInputClasses.disabled} .${outlinedInputClasses.notchedOutline}`]: { + borderColor: (theme.vars || theme).palette.action.disabled, + }, + }, + }, + { + props: ({ ownerState }) => ownerState.startAdornment, + style: { + paddingLeft: 14, + }, + }, + { + props: ({ ownerState }) => ownerState.endAdornment, + style: { + paddingRight: 14, + }, + }, + { + props: ({ ownerState }) => ownerState.multiline, + style: { + padding: '16.5px 14px', + }, + }, + { + props: ({ ownerState, size }) => ownerState.multiline && size === 'small', + style: { + padding: '8.5px 14px', + }, + }, + ], }; }); @@ -98,7 +128,7 @@ const OutlinedInputInput = styled(InputBaseInput, { name: 'MuiOutlinedInput', slot: 'Input', overridesResolver: inputBaseInputOverridesResolver, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ padding: '16.5px 14px', ...(!theme.vars && { '&:-webkit-autofill': { @@ -120,18 +150,34 @@ const OutlinedInputInput = styled(InputBaseInput, { }, }, }), - ...(ownerState.size === 'small' && { - padding: '8.5px 14px', - }), - ...(ownerState.multiline && { - padding: 0, - }), - ...(ownerState.startAdornment && { - paddingLeft: 0, - }), - ...(ownerState.endAdornment && { - paddingRight: 0, - }), + variants: [ + { + props: { + size: 'small', + }, + style: { + padding: '8.5px 14px', + }, + }, + { + props: ({ ownerState }) => ownerState.multiline, + style: { + padding: 0, + }, + }, + { + props: ({ ownerState }) => ownerState.startAdornment, + style: { + paddingLeft: 0, + }, + }, + { + props: ({ ownerState }) => ownerState.endAdornment, + style: { + paddingRight: 0, + }, + }, + ], })); const OutlinedInput = React.forwardRef(function OutlinedInput(inProps, ref) { @@ -386,6 +432,8 @@ OutlinedInput.propTypes /* remove-proptypes */ = { value: PropTypes.any, }; -OutlinedInput.muiName = 'Input'; +if (OutlinedInput) { + OutlinedInput.muiName = 'Input'; +} export default OutlinedInput; diff --git a/packages/mui-material/src/Pagination/Pagination.js b/packages/mui-material/src/Pagination/Pagination.js index 659f4588fd1989..db3cd1824bb646 100644 --- a/packages/mui-material/src/Pagination/Pagination.js +++ b/packages/mui-material/src/Pagination/Pagination.js @@ -4,11 +4,12 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import integerPropType from '@mui/utils/integerPropType'; -import useThemeProps from '../styles/useThemeProps'; import { getPaginationUtilityClass } from './paginationClasses'; import usePagination from '../usePagination'; import PaginationItem from '../PaginationItem'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; + +const useThemeProps = createUseThemeProps('MuiPagination'); const useUtilityClasses = (ownerState) => { const { classes, variant } = ownerState; diff --git a/packages/mui-material/src/Paper/Paper.js b/packages/mui-material/src/Paper/Paper.js index 7f0d449c86c278..fbb7d90343eb9f 100644 --- a/packages/mui-material/src/Paper/Paper.js +++ b/packages/mui-material/src/Paper/Paper.js @@ -6,12 +6,13 @@ import integerPropType from '@mui/utils/integerPropType'; import chainPropTypes from '@mui/utils/chainPropTypes'; import composeClasses from '@mui/utils/composeClasses'; import { alpha } from '@mui/system/colorManipulator'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import getOverlayAlpha from '../styles/getOverlayAlpha'; -import useThemeProps from '../styles/useThemeProps'; import useTheme from '../styles/useTheme'; import { getPaperUtilityClass } from './paperClasses'; +const useThemeProps = createUseThemeProps('MuiPaper'); + const useUtilityClasses = (ownerState) => { const { square, elevation, variant, classes } = ownerState; @@ -40,33 +41,40 @@ const PaperRoot = styled('div', { ownerState.variant === 'elevation' && styles[`elevation${ownerState.elevation}`], ]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ backgroundColor: (theme.vars || theme).palette.background.paper, color: (theme.vars || theme).palette.text.primary, transition: theme.transitions.create('box-shadow'), - ...(!ownerState.square && { - borderRadius: theme.shape.borderRadius, - }), - ...(ownerState.variant === 'outlined' && { - border: `1px solid ${(theme.vars || theme).palette.divider}`, - }), - ...(ownerState.variant === 'elevation' && { - boxShadow: (theme.vars || theme).shadows[ownerState.elevation], - ...(!theme.vars && - theme.palette.mode === 'dark' && { - backgroundImage: `linear-gradient(${alpha( - '#fff', - getOverlayAlpha(ownerState.elevation), - )}, ${alpha('#fff', getOverlayAlpha(ownerState.elevation))})`, - }), - ...(theme.vars && { - backgroundImage: theme.vars.overlays?.[ownerState.elevation], - }), - }), + variants: [ + { + props: ({ ownerState }) => !ownerState.square, + style: { + borderRadius: theme.shape.borderRadius, + }, + }, + { + props: { + variant: 'outlined', + }, + style: { + border: `1px solid ${(theme.vars || theme).palette.divider}`, + }, + }, + { + props: { + variant: 'elevation', + }, + style: { + boxShadow: 'var(--Paper-shadow)', + backgroundImage: 'var(--Paper-overlay)', + }, + }, + ], })); const Paper = React.forwardRef(function Paper(inProps, ref) { const props = useThemeProps({ props: inProps, name: 'MuiPaper' }); + const theme = useTheme(); const { className, @@ -88,8 +96,6 @@ const Paper = React.forwardRef(function Paper(inProps, ref) { const classes = useUtilityClasses(ownerState); if (process.env.NODE_ENV !== 'production') { - // eslint-disable-next-line react-hooks/rules-of-hooks - const theme = useTheme(); if (theme.shadows[elevation] === undefined) { console.error( [ @@ -107,6 +113,22 @@ const Paper = React.forwardRef(function Paper(inProps, ref) { className={clsx(classes.root, className)} ref={ref} {...other} + style={{ + ...(variant === 'elevation' && { + '--Paper-shadow': (theme.vars || theme).shadows[elevation], + ...(theme.vars && { + '--Paper-overlay': theme.overlays?.[elevation], + }), + ...(!theme.vars && + theme.palette.mode === 'dark' && { + '--Paper-overlay': `linear-gradient(${alpha( + '#fff', + getOverlayAlpha(elevation), + )}, ${alpha('#fff', getOverlayAlpha(elevation))})`, + }), + }), + ...other.style, + }} /> ); }); @@ -153,6 +175,10 @@ Paper.propTypes /* remove-proptypes */ = { * @default false */ square: PropTypes.bool, + /** + * @ignore + */ + style: PropTypes.object, /** * The system prop that allows defining system overrides as well as additional CSS styles. */ diff --git a/packages/mui-material/src/Radio/Radio.js b/packages/mui-material/src/Radio/Radio.js index 04e8e6d2cfacb5..ff0cc0e8f0265c 100644 --- a/packages/mui-material/src/Radio/Radio.js +++ b/packages/mui-material/src/Radio/Radio.js @@ -11,7 +11,7 @@ import capitalize from '../utils/capitalize'; import createChainedFunction from '../utils/createChainedFunction'; import useRadioGroup from '../RadioGroup/useRadioGroup'; import radioClasses, { getRadioUtilityClass } from './radioClasses'; -import { rootShouldForwardProp } from '../styles/styled'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; import { styled, createUseThemeProps } from '../zero-styled'; const useThemeProps = createUseThemeProps('MuiRadio'); @@ -118,10 +118,12 @@ const Radio = React.forwardRef(function Radio(inProps, ref) { onChange: onChangeProp, size = 'medium', className, + disableRipple = false, ...other } = props; const ownerState = { ...props, + disableRipple, color, size, }; diff --git a/packages/mui-material/src/Radio/RadioButtonIcon.js b/packages/mui-material/src/Radio/RadioButtonIcon.js index 817981d374f4de..7db83617bf8e97 100644 --- a/packages/mui-material/src/Radio/RadioButtonIcon.js +++ b/packages/mui-material/src/Radio/RadioButtonIcon.js @@ -3,7 +3,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import RadioButtonUncheckedIcon from '../internal/svg-icons/RadioButtonUnchecked'; import RadioButtonCheckedIcon from '../internal/svg-icons/RadioButtonChecked'; -import { rootShouldForwardProp } from '../styles/styled'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; import { styled } from '../zero-styled'; const RadioButtonIconRoot = styled('span', { shouldForwardProp: rootShouldForwardProp })({ diff --git a/packages/mui-material/src/Rating/Rating.js b/packages/mui-material/src/Rating/Rating.js index 8e17b96b169371..a61b3dde83c6e6 100644 --- a/packages/mui-material/src/Rating/Rating.js +++ b/packages/mui-material/src/Rating/Rating.js @@ -16,10 +16,12 @@ import { } from '../utils'; import Star from '../internal/svg-icons/Star'; import StarBorder from '../internal/svg-icons/StarBorder'; -import useThemeProps from '../styles/useThemeProps'; -import styled, { slotShouldForwardProp } from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; +import slotShouldForwardProp from '../styles/slotShouldForwardProp'; import ratingClasses, { getRatingUtilityClass } from './ratingClasses'; +const useThemeProps = createUseThemeProps('MuiRating'); + function getDecimalPrecision(num) { const decimalPart = num.toString().split('.')[1]; return decimalPart ? decimalPart.length : 0; diff --git a/packages/mui-material/src/Select/Select.js b/packages/mui-material/src/Select/Select.js index 69bc3ea931cddb..16df3a3469ab84 100644 --- a/packages/mui-material/src/Select/Select.js +++ b/packages/mui-material/src/Select/Select.js @@ -13,7 +13,8 @@ import FilledInput from '../FilledInput'; import OutlinedInput from '../OutlinedInput'; import useThemeProps from '../styles/useThemeProps'; import useForkRef from '../utils/useForkRef'; -import styled, { rootShouldForwardProp } from '../styles/styled'; +import { styled } from '../zero-styled'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; const useUtilityClasses = (ownerState) => { const { classes } = ownerState; diff --git a/packages/mui-material/src/Select/SelectInput.js b/packages/mui-material/src/Select/SelectInput.js index 54741070da1a85..944a7e29759277 100644 --- a/packages/mui-material/src/Select/SelectInput.js +++ b/packages/mui-material/src/Select/SelectInput.js @@ -10,17 +10,15 @@ import refType from '@mui/utils/refType'; import ownerDocument from '../utils/ownerDocument'; import capitalize from '../utils/capitalize'; import Menu from '../Menu/Menu'; -import { - nativeSelectSelectStyles, - nativeSelectIconStyles, -} from '../NativeSelect/NativeSelectInput'; +import { StyledSelectSelect, StyledSelectIcon } from '../NativeSelect/NativeSelectInput'; import { isFilled } from '../InputBase/utils'; -import styled, { slotShouldForwardProp } from '../styles/styled'; +import { styled } from '../zero-styled'; +import slotShouldForwardProp from '../styles/slotShouldForwardProp'; import useForkRef from '../utils/useForkRef'; import useControlled from '../utils/useControlled'; import selectClasses, { getSelectUtilityClasses } from './selectClasses'; -const SelectSelect = styled('div', { +const SelectSelect = styled(StyledSelectSelect, { name: 'MuiSelect', slot: 'Select', overridesResolver: (props, styles) => { @@ -33,7 +31,7 @@ const SelectSelect = styled('div', { { [`&.${selectClasses.multiple}`]: styles.multiple }, ]; }, -})(nativeSelectSelectStyles, { +})({ // Win specificity over the input base [`&.${selectClasses.select}`]: { height: 'auto', // Resets for multiple select with chips @@ -44,7 +42,7 @@ const SelectSelect = styled('div', { }, }); -const SelectIcon = styled('svg', { +const SelectIcon = styled(StyledSelectIcon, { name: 'MuiSelect', slot: 'Icon', overridesResolver: (props, styles) => { @@ -55,7 +53,7 @@ const SelectIcon = styled('svg', { ownerState.open && styles.iconOpen, ]; }, -})(nativeSelectIconStyles); +})({}); const SelectNativeInput = styled('input', { shouldForwardProp: (prop) => slotShouldForwardProp(prop) && prop !== 'classes', @@ -493,6 +491,7 @@ const SelectInput = React.forwardRef(function SelectInput(props, ref) { return ( { const { classes, variant, animation, hasChildren, width, height } = ownerState; @@ -55,6 +55,23 @@ const waveKeyframe = keyframes` } `; +// This implementation is for supporting both Styled-components v4+ and Pigment CSS. +// A global animation has to be created here for Styled-components v4+ (https://github.com/styled-components/styled-components/blob/main/packages/styled-components/src/utils/errors.md#12). +// which can be done by checking typeof indeterminate1Keyframe !== 'string' (at runtime, Pigment CSS transform keyframes`` to a string). +const pulseAnimation = + typeof pulseKeyframe !== 'string' + ? css` + animation: ${pulseKeyframe} 2s ease-in-out 0.5s infinite; + ` + : null; + +const waveAnimation = + typeof waveKeyframe !== 'string' + ? css` + animation: ${waveKeyframe} 2s linear 0.5s infinite; + ` + : null; + const SkeletonRoot = styled('span', { name: 'MuiSkeleton', slot: 'Root', @@ -70,84 +87,117 @@ const SkeletonRoot = styled('span', { ownerState.hasChildren && !ownerState.height && styles.heightAuto, ]; }, -})( - ({ theme, ownerState }) => { - const radiusUnit = getUnit(theme.shape.borderRadius) || 'px'; - const radiusValue = toUnitless(theme.shape.borderRadius); - - return { - display: 'block', - // Create a "on paper" color with sufficient contrast retaining the color - backgroundColor: theme.vars - ? theme.vars.palette.Skeleton.bg - : alpha(theme.palette.text.primary, theme.palette.mode === 'light' ? 0.11 : 0.13), - height: '1.2em', - ...(ownerState.variant === 'text' && { - marginTop: 0, - marginBottom: 0, - height: 'auto', - transformOrigin: '0 55%', - transform: 'scale(1, 0.60)', - borderRadius: `${radiusValue}${radiusUnit}/${ - Math.round((radiusValue / 0.6) * 10) / 10 - }${radiusUnit}`, - '&:empty:before': { - content: '"\\00a0"', +})(({ theme }) => { + const radiusUnit = getUnit(theme.shape.borderRadius) || 'px'; + const radiusValue = toUnitless(theme.shape.borderRadius); + + return { + display: 'block', + // Create a "on paper" color with sufficient contrast retaining the color + backgroundColor: theme.vars + ? theme.vars.palette.Skeleton.bg + : alpha(theme.palette.text.primary, theme.palette.mode === 'light' ? 0.11 : 0.13), + height: '1.2em', + variants: [ + { + props: { + variant: 'text', + }, + style: { + marginTop: 0, + marginBottom: 0, + height: 'auto', + transformOrigin: '0 55%', + transform: 'scale(1, 0.60)', + borderRadius: `${radiusValue}${radiusUnit}/${ + Math.round((radiusValue / 0.6) * 10) / 10 + }${radiusUnit}`, + '&:empty:before': { + content: '"\\00a0"', + }, + }, + }, + { + props: { + variant: 'circular', + }, + style: { + borderRadius: '50%', }, - }), - ...(ownerState.variant === 'circular' && { - borderRadius: '50%', - }), - ...(ownerState.variant === 'rounded' && { - borderRadius: (theme.vars || theme).shape.borderRadius, - }), - ...(ownerState.hasChildren && { - '& > *': { - visibility: 'hidden', + }, + { + props: { + variant: 'rounded', }, - }), - ...(ownerState.hasChildren && - !ownerState.width && { + style: { + borderRadius: (theme.vars || theme).shape.borderRadius, + }, + }, + { + props: ({ ownerState }) => ownerState.hasChildren, + style: { + '& > *': { + visibility: 'hidden', + }, + }, + }, + { + props: ({ ownerState }) => ownerState.hasChildren && !ownerState.width, + style: { maxWidth: 'fit-content', - }), - ...(ownerState.hasChildren && - !ownerState.height && { + }, + }, + { + props: ({ ownerState }) => ownerState.hasChildren && !ownerState.height, + style: { height: 'auto', - }), - }; - }, - ({ ownerState }) => - ownerState.animation === 'pulse' && - css` - animation: ${pulseKeyframe} 2s ease-in-out 0.5s infinite; - `, - ({ ownerState, theme }) => - ownerState.animation === 'wave' && - css` - position: relative; - overflow: hidden; - - /* Fix bug in Safari https://bugs.webkit.org/show_bug.cgi?id=68196 */ - -webkit-mask-image: -webkit-radial-gradient(white, black); - - &::after { - animation: ${waveKeyframe} 2s linear 0.5s infinite; - background: linear-gradient( - 90deg, - transparent, - ${(theme.vars || theme).palette.action.hover}, - transparent - ); - content: ''; - position: absolute; - transform: translateX(-100%); /* Avoid flash during server-side hydration */ - bottom: 0; - left: 0; - right: 0; - top: 0; - } - `, -); + }, + }, + { + props: { + animation: 'pulse', + }, + style: pulseAnimation || { + animation: `${pulseKeyframe} 2s ease-in-out 0.5s infinite`, + }, + }, + { + props: { + animation: 'wave', + }, + style: { + position: 'relative', + overflow: 'hidden', + /* Fix bug in Safari https://bugs.webkit.org/show_bug.cgi?id=68196 */ + WebkitMaskImage: '-webkit-radial-gradient(white, black)', + '&::after': { + background: `linear-gradient( + 90deg, + transparent, + ${(theme.vars || theme).palette.action.hover}, + transparent + )`, + content: '""', + position: 'absolute', + transform: 'translateX(-100%)' /* Avoid flash during server-side hydration */, + bottom: 0, + left: 0, + right: 0, + top: 0, + }, + }, + }, + { + props: { + animation: 'wave', + }, + style: waveAnimation || { + animation: `${waveKeyframe} 2s linear 0.5s infinite`, + }, + }, + ], + }; +}); const Skeleton = React.forwardRef(function Skeleton(inProps, ref) { const props = useThemeProps({ props: inProps, name: 'MuiSkeleton' }); diff --git a/packages/mui-material/src/Snackbar/Snackbar.js b/packages/mui-material/src/Snackbar/Snackbar.js index df3cabca60fe96..3b731e05c71c48 100644 --- a/packages/mui-material/src/Snackbar/Snackbar.js +++ b/packages/mui-material/src/Snackbar/Snackbar.js @@ -5,14 +5,15 @@ import { useSlotProps } from '@mui/base/utils'; import composeClasses from '@mui/utils/composeClasses'; import { ClickAwayListener } from '@mui/base/ClickAwayListener'; import { useSnackbar } from '@mui/base/useSnackbar'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import useTheme from '../styles/useTheme'; -import useThemeProps from '../styles/useThemeProps'; import capitalize from '../utils/capitalize'; import Grow from '../Grow'; import SnackbarContent from '../SnackbarContent'; import { getSnackbarUtilityClass } from './snackbarClasses'; +const useThemeProps = createUseThemeProps('MuiSnackbar'); + const useUtilityClasses = (ownerState) => { const { classes, anchorOrigin } = ownerState; @@ -41,38 +42,55 @@ const SnackbarRoot = styled('div', { ], ]; }, -})(({ theme, ownerState }) => { - const center = { - left: '50%', - right: 'auto', - transform: 'translateX(-50%)', - }; - - return { - zIndex: (theme.vars || theme).zIndex.snackbar, - position: 'fixed', - display: 'flex', - left: 8, - right: 8, - justifyContent: 'center', - alignItems: 'center', - ...(ownerState.anchorOrigin.vertical === 'top' ? { top: 8 } : { bottom: 8 }), - ...(ownerState.anchorOrigin.horizontal === 'left' && { justifyContent: 'flex-start' }), - ...(ownerState.anchorOrigin.horizontal === 'right' && { justifyContent: 'flex-end' }), - [theme.breakpoints.up('sm')]: { - ...(ownerState.anchorOrigin.vertical === 'top' ? { top: 24 } : { bottom: 24 }), - ...(ownerState.anchorOrigin.horizontal === 'center' && center), - ...(ownerState.anchorOrigin.horizontal === 'left' && { - left: 24, - right: 'auto', - }), - ...(ownerState.anchorOrigin.horizontal === 'right' && { - right: 24, - left: 'auto', - }), +})(({ theme }) => ({ + zIndex: (theme.vars || theme).zIndex.snackbar, + position: 'fixed', + display: 'flex', + left: 8, + right: 8, + justifyContent: 'center', + alignItems: 'center', + variants: [ + { + props: ({ ownerState }) => ownerState.anchorOrigin.vertical === 'top', + style: { top: 8, [theme.breakpoints.up('sm')]: { top: 24 } }, }, - }; -}); + { + props: ({ ownerState }) => ownerState.anchorOrigin.vertical !== 'top', + style: { bottom: 8, [theme.breakpoints.up('sm')]: { bottom: 24 } }, + }, + { + props: ({ ownerState }) => ownerState.anchorOrigin.horizontal === 'left', + style: { + justifyContent: 'flex-start', + [theme.breakpoints.up('sm')]: { + left: 24, + right: 'auto', + }, + }, + }, + { + props: ({ ownerState }) => ownerState.anchorOrigin.horizontal === 'right', + style: { + justifyContent: 'flex-end', + [theme.breakpoints.up('sm')]: { + right: 24, + left: 'auto', + }, + }, + }, + { + props: ({ ownerState }) => ownerState.anchorOrigin.horizontal === 'center', + style: { + [theme.breakpoints.up('sm')]: { + left: '50%', + right: 'auto', + transform: 'translateX(-50%)', + }, + }, + }, + ], +})); const Snackbar = React.forwardRef(function Snackbar(inProps, ref) { const props = useThemeProps({ props: inProps, name: 'MuiSnackbar' }); diff --git a/packages/mui-material/src/SnackbarContent/SnackbarContent.js b/packages/mui-material/src/SnackbarContent/SnackbarContent.js index cdee122e3185c0..10e1e774167f23 100644 --- a/packages/mui-material/src/SnackbarContent/SnackbarContent.js +++ b/packages/mui-material/src/SnackbarContent/SnackbarContent.js @@ -4,11 +4,12 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import { emphasize } from '@mui/system/colorManipulator'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import Paper from '../Paper'; import { getSnackbarContentUtilityClass } from './snackbarContentClasses'; +const useThemeProps = createUseThemeProps('MuiSnackbarContent'); + const useUtilityClasses = (ownerState) => { const { classes } = ownerState; diff --git a/packages/mui-material/src/SpeedDial/SpeedDial.js b/packages/mui-material/src/SpeedDial/SpeedDial.js index cb35e3a25de29d..f65f03100530c8 100644 --- a/packages/mui-material/src/SpeedDial/SpeedDial.js +++ b/packages/mui-material/src/SpeedDial/SpeedDial.js @@ -6,8 +6,7 @@ import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import useTimeout from '@mui/utils/useTimeout'; import clamp from '@mui/utils/clamp'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import useTheme from '../styles/useTheme'; import Zoom from '../Zoom'; import Fab from '../Fab'; @@ -18,6 +17,8 @@ import useControlled from '../utils/useControlled'; import speedDialClasses, { getSpeedDialUtilityClass } from './speedDialClasses'; import useSlot from '../utils/useSlot'; +const useThemeProps = createUseThemeProps('MuiSpeedDial'); + const useUtilityClasses = (ownerState) => { const { classes, open, direction } = ownerState; @@ -51,43 +52,65 @@ const SpeedDialRoot = styled('div', { return [styles.root, styles[`direction${capitalize(ownerState.direction)}`]]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ zIndex: (theme.vars || theme).zIndex.speedDial, display: 'flex', alignItems: 'center', pointerEvents: 'none', - ...(ownerState.direction === 'up' && { - flexDirection: 'column-reverse', - [`& .${speedDialClasses.actions}`]: { - flexDirection: 'column-reverse', - marginBottom: -dialRadius, - paddingBottom: spacingActions + dialRadius, + variants: [ + { + props: { + direction: 'up', + }, + style: { + flexDirection: 'column-reverse', + [`& .${speedDialClasses.actions}`]: { + flexDirection: 'column-reverse', + marginBottom: -dialRadius, + paddingBottom: spacingActions + dialRadius, + }, + }, }, - }), - ...(ownerState.direction === 'down' && { - flexDirection: 'column', - [`& .${speedDialClasses.actions}`]: { - flexDirection: 'column', - marginTop: -dialRadius, - paddingTop: spacingActions + dialRadius, + { + props: { + direction: 'down', + }, + style: { + flexDirection: 'column', + [`& .${speedDialClasses.actions}`]: { + flexDirection: 'column', + marginTop: -dialRadius, + paddingTop: spacingActions + dialRadius, + }, + }, }, - }), - ...(ownerState.direction === 'left' && { - flexDirection: 'row-reverse', - [`& .${speedDialClasses.actions}`]: { - flexDirection: 'row-reverse', - marginRight: -dialRadius, - paddingRight: spacingActions + dialRadius, + { + props: { + direction: 'left', + }, + style: { + flexDirection: 'row-reverse', + [`& .${speedDialClasses.actions}`]: { + flexDirection: 'row-reverse', + marginRight: -dialRadius, + paddingRight: spacingActions + dialRadius, + }, + }, }, - }), - ...(ownerState.direction === 'right' && { - flexDirection: 'row', - [`& .${speedDialClasses.actions}`]: { - flexDirection: 'row', - marginLeft: -dialRadius, - paddingLeft: spacingActions + dialRadius, + { + props: { + direction: 'right', + }, + style: { + flexDirection: 'row', + [`& .${speedDialClasses.actions}`]: { + flexDirection: 'row', + marginLeft: -dialRadius, + paddingLeft: spacingActions + dialRadius, + }, + }, }, - }), + ], })); const SpeedDialFab = styled(Fab, { @@ -106,14 +129,19 @@ const SpeedDialActions = styled('div', { return [styles.actions, !ownerState.open && styles.actionsClosed]; }, -})(({ ownerState }) => ({ +})({ display: 'flex', pointerEvents: 'auto', - ...(!ownerState.open && { - transition: 'top 0s linear 0.2s', - pointerEvents: 'none', - }), -})); + variants: [ + { + props: ({ ownerState }) => !ownerState.open, + style: { + transition: 'top 0s linear 0.2s', + pointerEvents: 'none', + }, + }, + ], +}); const SpeedDial = React.forwardRef(function SpeedDial(inProps, ref) { const props = useThemeProps({ props: inProps, name: 'MuiSpeedDial' }); diff --git a/packages/mui-material/src/SpeedDialAction/SpeedDialAction.js b/packages/mui-material/src/SpeedDialAction/SpeedDialAction.js index b1a44948531dc8..50729eccf4a4f1 100644 --- a/packages/mui-material/src/SpeedDialAction/SpeedDialAction.js +++ b/packages/mui-material/src/SpeedDialAction/SpeedDialAction.js @@ -5,13 +5,14 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import { emphasize } from '@mui/system/colorManipulator'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import Fab from '../Fab'; import Tooltip from '../Tooltip'; import capitalize from '../utils/capitalize'; import speedDialActionClasses, { getSpeedDialActionUtilityClass } from './speedDialActionClasses'; +const useThemeProps = createUseThemeProps('MuiSpeedDialAction'); + const useUtilityClasses = (ownerState) => { const { open, tooltipPlacement, classes } = ownerState; @@ -37,7 +38,7 @@ const SpeedDialActionFab = styled(Fab, { return [styles.fab, !ownerState.open && styles.fabClosed]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ margin: 8, color: (theme.vars || theme).palette.text.secondary, backgroundColor: (theme.vars || theme).palette.background.paper, @@ -50,10 +51,15 @@ const SpeedDialActionFab = styled(Fab, { duration: theme.transitions.duration.shorter, })}, opacity 0.8s`, opacity: 1, - ...(!ownerState.open && { - opacity: 0, - transform: 'scale(0)', - }), + variants: [ + { + props: ({ ownerState }) => !ownerState.open, + style: { + opacity: 0, + transform: 'scale(0)', + }, + }, + ], })); const SpeedDialActionStaticTooltip = styled('span', { @@ -68,7 +74,7 @@ const SpeedDialActionStaticTooltip = styled('span', { styles[`tooltipPlacement${capitalize(ownerState.tooltipPlacement)}`], ]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ position: 'relative', display: 'flex', alignItems: 'center', @@ -77,21 +83,42 @@ const SpeedDialActionStaticTooltip = styled('span', { duration: theme.transitions.duration.shorter, }), opacity: 1, - ...(!ownerState.open && { - opacity: 0, - transform: 'scale(0.5)', - }), - ...(ownerState.tooltipPlacement === 'left' && { - transformOrigin: '100% 50%', - right: '100%', - marginRight: 8, - }), - ...(ownerState.tooltipPlacement === 'right' && { - transformOrigin: '0% 50%', - left: '100%', - marginLeft: 8, - }), }, + variants: [ + { + props: ({ ownerState }) => !ownerState.open, + style: { + [`& .${speedDialActionClasses.staticTooltipLabel}`]: { + opacity: 0, + transform: 'scale(0.5)', + }, + }, + }, + { + props: { + tooltipPlacement: 'left', + }, + style: { + [`& .${speedDialActionClasses.staticTooltipLabel}`]: { + transformOrigin: '100% 50%', + right: '100%', + marginRight: 8, + }, + }, + }, + { + props: { + tooltipPlacement: 'right', + }, + style: { + [`& .${speedDialActionClasses.staticTooltipLabel}`]: { + transformOrigin: '0% 50%', + left: '100%', + marginLeft: 8, + }, + }, + }, + ], })); const SpeedDialActionStaticTooltipLabel = styled('span', { diff --git a/packages/mui-material/src/SpeedDialIcon/SpeedDialIcon.js b/packages/mui-material/src/SpeedDialIcon/SpeedDialIcon.js index 5286882d359bcd..06dfaebd0ae7bb 100644 --- a/packages/mui-material/src/SpeedDialIcon/SpeedDialIcon.js +++ b/packages/mui-material/src/SpeedDialIcon/SpeedDialIcon.js @@ -3,11 +3,12 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import AddIcon from '../internal/svg-icons/Add'; import speedDialIconClasses, { getSpeedDialIconUtilityClass } from './speedDialIconClasses'; +const useThemeProps = createUseThemeProps('MuiSpeedDialIcon'); + const useUtilityClasses = (ownerState) => { const { classes, open, openIcon } = ownerState; @@ -38,18 +39,12 @@ const SpeedDialIconRoot = styled('span', { styles.root, ]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ height: 24, [`& .${speedDialIconClasses.icon}`]: { transition: theme.transitions.create(['transform', 'opacity'], { duration: theme.transitions.duration.short, }), - ...(ownerState.open && { - transform: 'rotate(45deg)', - ...(ownerState.openIcon && { - opacity: 0, - }), - }), }, [`& .${speedDialIconClasses.openIcon}`]: { position: 'absolute', @@ -58,11 +53,34 @@ const SpeedDialIconRoot = styled('span', { }), opacity: 0, transform: 'rotate(-45deg)', - ...(ownerState.open && { - transform: 'rotate(0deg)', - opacity: 1, - }), }, + variants: [ + { + props: ({ ownerState }) => ownerState.open, + style: { + [`& .${speedDialIconClasses.icon}`]: { + transform: 'rotate(45deg)', + }, + }, + }, + { + props: ({ ownerState }) => ownerState.open && ownerState.openIcon, + style: { + [`& .${speedDialIconClasses.icon}`]: { + opacity: 0, + }, + }, + }, + { + props: ({ ownerState }) => ownerState.open, + style: { + [`& .${speedDialIconClasses.openIcon}`]: { + transform: 'rotate(0deg)', + opacity: 1, + }, + }, + }, + ], })); const SpeedDialIcon = React.forwardRef(function SpeedDialIcon(inProps, ref) { diff --git a/packages/mui-material/src/SwipeableDrawer/SwipeArea.js b/packages/mui-material/src/SwipeableDrawer/SwipeArea.js index 30b82178ed56ae..c3855344bc11c4 100644 --- a/packages/mui-material/src/SwipeableDrawer/SwipeArea.js +++ b/packages/mui-material/src/SwipeableDrawer/SwipeArea.js @@ -2,35 +2,56 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; -import styled, { rootShouldForwardProp } from '../styles/styled'; +import { styled } from '../zero-styled'; +import rootShouldForwardProp from '../styles/rootShouldForwardProp'; import capitalize from '../utils/capitalize'; import { isHorizontal } from '../Drawer/Drawer'; -const SwipeAreaRoot = styled('div', { shouldForwardProp: rootShouldForwardProp })( - ({ theme, ownerState }) => ({ - position: 'fixed', - top: 0, - left: 0, - bottom: 0, - zIndex: theme.zIndex.drawer - 1, - ...(ownerState.anchor === 'left' && { - right: 'auto', - }), - ...(ownerState.anchor === 'right' && { - left: 'auto', - right: 0, - }), - ...(ownerState.anchor === 'top' && { - bottom: 'auto', - right: 0, - }), - ...(ownerState.anchor === 'bottom' && { - top: 'auto', - bottom: 0, - right: 0, - }), - }), -); +const SwipeAreaRoot = styled('div', { shouldForwardProp: rootShouldForwardProp })(({ theme }) => ({ + position: 'fixed', + top: 0, + left: 0, + bottom: 0, + zIndex: theme.zIndex.drawer - 1, + variants: [ + { + props: { + anchor: 'left', + }, + style: { + right: 'auto', + }, + }, + { + props: { + anchor: 'right', + }, + style: { + left: 'auto', + right: 0, + }, + }, + { + props: { + anchor: 'top', + }, + style: { + bottom: 'auto', + right: 0, + }, + }, + { + props: { + anchor: 'bottom', + }, + style: { + top: 'auto', + bottom: 0, + right: 0, + }, + }, + ], +})); /** * @ignore - internal component. diff --git a/packages/mui-material/src/Tab/Tab.js b/packages/mui-material/src/Tab/Tab.js index 43d53422a76454..b25d9a5eae0217 100644 --- a/packages/mui-material/src/Tab/Tab.js +++ b/packages/mui-material/src/Tab/Tab.js @@ -5,11 +5,12 @@ import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import ButtonBase from '../ButtonBase'; import capitalize from '../utils/capitalize'; -import useThemeProps from '../styles/useThemeProps'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import unsupportedProp from '../utils/unsupportedProp'; import tabClasses, { getTabUtilityClass } from './tabClasses'; +const useThemeProps = createUseThemeProps('MuiTab'); + const useUtilityClasses = (ownerState) => { const { classes, textColor, fullWidth, wrapped, icon, label, selected, disabled } = ownerState; @@ -43,7 +44,7 @@ const TabRoot = styled(ButtonBase, { ownerState.wrapped && styles.wrapped, ]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ ...theme.typography.button, maxWidth: 360, minWidth: 90, @@ -54,68 +55,128 @@ const TabRoot = styled(ButtonBase, { overflow: 'hidden', whiteSpace: 'normal', textAlign: 'center', - ...(ownerState.label && { - flexDirection: - ownerState.iconPosition === 'top' || ownerState.iconPosition === 'bottom' ? 'column' : 'row', - }), lineHeight: 1.25, - ...(ownerState.icon && - ownerState.label && { - minHeight: 72, - paddingTop: 9, - paddingBottom: 9, - [`& > .${tabClasses.iconWrapper}`]: { - ...(ownerState.iconPosition === 'top' && { + variants: [ + { + props: ({ ownerState }) => + ownerState.label && + (ownerState.iconPosition === 'top' || ownerState.iconPosition === 'bottom'), + style: { + flexDirection: 'column', + }, + }, + { + props: ({ ownerState }) => + ownerState.label && + ownerState.iconPosition !== 'top' && + ownerState.iconPosition !== 'bottom', + style: { + flexDirection: 'row', + }, + }, + { + props: ({ ownerState }) => ownerState.icon && ownerState.label, + style: { + minHeight: 72, + paddingTop: 9, + paddingBottom: 9, + }, + }, + { + props: ({ ownerState, iconPosition }) => + ownerState.icon && ownerState.label && iconPosition === 'top', + style: { + [`& > .${tabClasses.iconWrapper}`]: { marginBottom: 6, - }), - ...(ownerState.iconPosition === 'bottom' && { + }, + }, + }, + { + props: ({ ownerState, iconPosition }) => + ownerState.icon && ownerState.label && iconPosition === 'bottom', + style: { + [`& > .${tabClasses.iconWrapper}`]: { marginTop: 6, - }), - ...(ownerState.iconPosition === 'start' && { + }, + }, + }, + { + props: ({ ownerState, iconPosition }) => + ownerState.icon && ownerState.label && iconPosition === 'start', + style: { + [`& > .${tabClasses.iconWrapper}`]: { marginRight: theme.spacing(1), - }), - ...(ownerState.iconPosition === 'end' && { + }, + }, + }, + { + props: ({ ownerState, iconPosition }) => + ownerState.icon && ownerState.label && iconPosition === 'end', + style: { + [`& > .${tabClasses.iconWrapper}`]: { marginLeft: theme.spacing(1), - }), + }, }, - }), - ...(ownerState.textColor === 'inherit' && { - color: 'inherit', - opacity: 0.6, // same opacity as theme.palette.text.secondary - [`&.${tabClasses.selected}`]: { - opacity: 1, }, - [`&.${tabClasses.disabled}`]: { - opacity: (theme.vars || theme).palette.action.disabledOpacity, + { + props: { + textColor: 'inherit', + }, + style: { + color: 'inherit', + opacity: 0.6, // same opacity as theme.palette.text.secondary + [`&.${tabClasses.selected}`]: { + opacity: 1, + }, + [`&.${tabClasses.disabled}`]: { + opacity: (theme.vars || theme).palette.action.disabledOpacity, + }, + }, }, - }), - ...(ownerState.textColor === 'primary' && { - color: (theme.vars || theme).palette.text.secondary, - [`&.${tabClasses.selected}`]: { - color: (theme.vars || theme).palette.primary.main, + { + props: { + textColor: 'primary', + }, + style: { + color: (theme.vars || theme).palette.text.secondary, + [`&.${tabClasses.selected}`]: { + color: (theme.vars || theme).palette.primary.main, + }, + [`&.${tabClasses.disabled}`]: { + color: (theme.vars || theme).palette.text.disabled, + }, + }, }, - [`&.${tabClasses.disabled}`]: { - color: (theme.vars || theme).palette.text.disabled, + { + props: { + textColor: 'secondary', + }, + style: { + color: (theme.vars || theme).palette.text.secondary, + [`&.${tabClasses.selected}`]: { + color: (theme.vars || theme).palette.secondary.main, + }, + [`&.${tabClasses.disabled}`]: { + color: (theme.vars || theme).palette.text.disabled, + }, + }, }, - }), - ...(ownerState.textColor === 'secondary' && { - color: (theme.vars || theme).palette.text.secondary, - [`&.${tabClasses.selected}`]: { - color: (theme.vars || theme).palette.secondary.main, + { + props: ({ ownerState }) => ownerState.fullWidth, + style: { + flexShrink: 1, + flexGrow: 1, + flexBasis: 0, + maxWidth: 'none', + }, }, - [`&.${tabClasses.disabled}`]: { - color: (theme.vars || theme).palette.text.disabled, + { + props: ({ ownerState }) => ownerState.wrapped, + style: { + fontSize: theme.typography.pxToRem(12), + }, }, - }), - ...(ownerState.fullWidth && { - flexShrink: 1, - flexGrow: 1, - flexBasis: 0, - maxWidth: 'none', - }), - ...(ownerState.wrapped && { - fontSize: theme.typography.pxToRem(12), - }), + ], })); const Tab = React.forwardRef(function Tab(inProps, ref) { diff --git a/packages/mui-material/src/TabScrollButton/TabScrollButton.js b/packages/mui-material/src/TabScrollButton/TabScrollButton.js index 9dcdd8fe8efbc3..e9a3fa1e476b20 100644 --- a/packages/mui-material/src/TabScrollButton/TabScrollButton.js +++ b/packages/mui-material/src/TabScrollButton/TabScrollButton.js @@ -9,10 +9,11 @@ import { useRtl } from '@mui/system/RtlProvider'; import KeyboardArrowLeft from '../internal/svg-icons/KeyboardArrowLeft'; import KeyboardArrowRight from '../internal/svg-icons/KeyboardArrowRight'; import ButtonBase from '../ButtonBase'; -import useThemeProps from '../styles/useThemeProps'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import tabScrollButtonClasses, { getTabScrollButtonUtilityClass } from './tabScrollButtonClasses'; +const useThemeProps = createUseThemeProps('MuiTabScrollButton'); + const useUtilityClasses = (ownerState) => { const { classes, orientation, disabled } = ownerState; @@ -31,21 +32,28 @@ const TabScrollButtonRoot = styled(ButtonBase, { return [styles.root, ownerState.orientation && styles[ownerState.orientation]]; }, -})(({ ownerState }) => ({ +})({ width: 40, flexShrink: 0, opacity: 0.8, [`&.${tabScrollButtonClasses.disabled}`]: { opacity: 0, }, - ...(ownerState.orientation === 'vertical' && { - width: '100%', - height: 40, - '& svg': { - transform: `rotate(${ownerState.isRtl ? -90 : 90}deg)`, + variants: [ + { + props: { + orientation: 'vertical', + }, + style: { + width: '100%', + height: 40, + '& svg': { + transform: 'var(--TabScrollButton-svgRotate)', + }, + }, }, - }), -})); + ], +}); const TabScrollButton = React.forwardRef(function TabScrollButton(inProps, ref) { const props = useThemeProps({ props: inProps, name: 'MuiTabScrollButton' }); @@ -95,6 +103,12 @@ const TabScrollButton = React.forwardRef(function TabScrollButton(inProps, ref) ownerState={ownerState} tabIndex={null} {...other} + style={{ + ...other.style, + ...(orientation === 'vertical' && { + '--TabScrollButton-svgRotate': `rotate(${isRtl ? -90 : 90}deg)`, + }), + }} > {direction === 'left' ? ( @@ -152,6 +166,10 @@ TabScrollButton.propTypes /* remove-proptypes */ = { EndScrollButtonIcon: PropTypes.elementType, StartScrollButtonIcon: PropTypes.elementType, }), + /** + * @ignore + */ + style: PropTypes.object, /** * The system prop that allows defining system overrides as well as additional CSS styles. */ diff --git a/packages/mui-material/src/Table/Table.js b/packages/mui-material/src/Table/Table.js index ee4e793dcaa1d6..d513e8e4528850 100644 --- a/packages/mui-material/src/Table/Table.js +++ b/packages/mui-material/src/Table/Table.js @@ -4,10 +4,11 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import TableContext from './TableContext'; -import useThemeProps from '../styles/useThemeProps'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getTableUtilityClass } from './tableClasses'; +const useThemeProps = createUseThemeProps('MuiTable'); + const useUtilityClasses = (ownerState) => { const { classes, stickyHeader } = ownerState; diff --git a/packages/mui-material/src/TableBody/TableBody.js b/packages/mui-material/src/TableBody/TableBody.js index 0fc5115e327055..9116e8274d0cb1 100644 --- a/packages/mui-material/src/TableBody/TableBody.js +++ b/packages/mui-material/src/TableBody/TableBody.js @@ -4,10 +4,11 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import Tablelvl2Context from '../Table/Tablelvl2Context'; -import useThemeProps from '../styles/useThemeProps'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getTableBodyUtilityClass } from './tableBodyClasses'; +const useThemeProps = createUseThemeProps('MuiTableBody'); + const useUtilityClasses = (ownerState) => { const { classes } = ownerState; diff --git a/packages/mui-material/src/TableCell/TableCell.js b/packages/mui-material/src/TableCell/TableCell.js index cf3860f2763af1..71a8c53e1013a2 100644 --- a/packages/mui-material/src/TableCell/TableCell.js +++ b/packages/mui-material/src/TableCell/TableCell.js @@ -7,10 +7,11 @@ import { darken, alpha, lighten } from '@mui/system/colorManipulator'; import capitalize from '../utils/capitalize'; import TableContext from '../Table/TableContext'; import Tablelvl2Context from '../Table/Tablelvl2Context'; -import useThemeProps from '../styles/useThemeProps'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import tableCellClasses, { getTableCellUtilityClass } from './tableCellClasses'; +const useThemeProps = createUseThemeProps('MuiTableCell'); + const useUtilityClasses = (ownerState) => { const { classes, variant, align, padding, size, stickyHeader } = ownerState; diff --git a/packages/mui-material/src/TableContainer/TableContainer.js b/packages/mui-material/src/TableContainer/TableContainer.js index 206d3b4295b7af..f786b6192e247b 100644 --- a/packages/mui-material/src/TableContainer/TableContainer.js +++ b/packages/mui-material/src/TableContainer/TableContainer.js @@ -3,10 +3,11 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; -import useThemeProps from '../styles/useThemeProps'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getTableContainerUtilityClass } from './tableContainerClasses'; +const useThemeProps = createUseThemeProps('MuiTableContainer'); + const useUtilityClasses = (ownerState) => { const { classes } = ownerState; diff --git a/packages/mui-material/src/TableFooter/TableFooter.js b/packages/mui-material/src/TableFooter/TableFooter.js index ca142c563b62d6..5de3b7d0a3909d 100644 --- a/packages/mui-material/src/TableFooter/TableFooter.js +++ b/packages/mui-material/src/TableFooter/TableFooter.js @@ -4,10 +4,11 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import Tablelvl2Context from '../Table/Tablelvl2Context'; -import useThemeProps from '../styles/useThemeProps'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getTableFooterUtilityClass } from './tableFooterClasses'; +const useThemeProps = createUseThemeProps('MuiTableFooter'); + const useUtilityClasses = (ownerState) => { const { classes } = ownerState; diff --git a/packages/mui-material/src/TableHead/TableHead.js b/packages/mui-material/src/TableHead/TableHead.js index 3a58974aa5ab09..32943035f0911b 100644 --- a/packages/mui-material/src/TableHead/TableHead.js +++ b/packages/mui-material/src/TableHead/TableHead.js @@ -4,10 +4,11 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import Tablelvl2Context from '../Table/Tablelvl2Context'; -import useThemeProps from '../styles/useThemeProps'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getTableHeadUtilityClass } from './tableHeadClasses'; +const useThemeProps = createUseThemeProps('MuiTableHead'); + const useUtilityClasses = (ownerState) => { const { classes } = ownerState; diff --git a/packages/mui-material/src/TablePagination/TablePagination.js b/packages/mui-material/src/TablePagination/TablePagination.js index 88dbd75c142c07..3aad5afa263e01 100644 --- a/packages/mui-material/src/TablePagination/TablePagination.js +++ b/packages/mui-material/src/TablePagination/TablePagination.js @@ -6,8 +6,7 @@ import integerPropType from '@mui/utils/integerPropType'; import chainPropTypes from '@mui/utils/chainPropTypes'; import { isHostComponent } from '@mui/base/utils'; import composeClasses from '@mui/utils/composeClasses'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import InputBase from '../InputBase'; import MenuItem from '../MenuItem'; import Select from '../Select'; @@ -17,6 +16,8 @@ import TablePaginationActions from './TablePaginationActions'; import useId from '../utils/useId'; import tablePaginationClasses, { getTablePaginationUtilityClass } from './tablePaginationClasses'; +const useThemeProps = createUseThemeProps('MuiTablePagination'); + const TablePaginationRoot = styled(TableCell, { name: 'MuiTablePagination', slot: 'Root', diff --git a/packages/mui-material/src/TableRow/TableRow.js b/packages/mui-material/src/TableRow/TableRow.js index 40612a6e0a9209..d96f9fce5745d4 100644 --- a/packages/mui-material/src/TableRow/TableRow.js +++ b/packages/mui-material/src/TableRow/TableRow.js @@ -5,10 +5,11 @@ import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import { alpha } from '@mui/system/colorManipulator'; import Tablelvl2Context from '../Table/Tablelvl2Context'; -import useThemeProps from '../styles/useThemeProps'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import tableRowClasses, { getTableRowUtilityClass } from './tableRowClasses'; +const useThemeProps = createUseThemeProps('MuiTableRow'); + const useUtilityClasses = (ownerState) => { const { classes, selected, hover, head, footer } = ownerState; diff --git a/packages/mui-material/src/TableSortLabel/TableSortLabel.js b/packages/mui-material/src/TableSortLabel/TableSortLabel.js index f2e174a41fb901..25d11cb4f40ca9 100644 --- a/packages/mui-material/src/TableSortLabel/TableSortLabel.js +++ b/packages/mui-material/src/TableSortLabel/TableSortLabel.js @@ -5,11 +5,12 @@ import PropTypes from 'prop-types'; import * as React from 'react'; import ButtonBase from '../ButtonBase'; import ArrowDownwardIcon from '../internal/svg-icons/ArrowDownward'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import capitalize from '../utils/capitalize'; import tableSortLabelClasses, { getTableSortLabelUtilityClass } from './tableSortLabelClasses'; +const useThemeProps = createUseThemeProps('MuiTableSortLabel'); + const useUtilityClasses = (ownerState) => { const { classes, direction, active } = ownerState; diff --git a/packages/mui-material/src/Tabs/Tabs.js b/packages/mui-material/src/Tabs/Tabs.js index dfbcd083803bd0..3bafb2efbb4ade 100644 --- a/packages/mui-material/src/Tabs/Tabs.js +++ b/packages/mui-material/src/Tabs/Tabs.js @@ -7,8 +7,7 @@ import refType from '@mui/utils/refType'; import { useSlotProps } from '@mui/base/utils'; import composeClasses from '@mui/utils/composeClasses'; import { useRtl } from '@mui/system/RtlProvider'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import useTheme from '../styles/useTheme'; import debounce from '../utils/debounce'; import { getNormalizedScrollLeft, detectScrollType } from '../utils/scrollLeft'; @@ -20,6 +19,8 @@ import tabsClasses, { getTabsUtilityClass } from './tabsClasses'; import ownerDocument from '../utils/ownerDocument'; import ownerWindow from '../utils/ownerWindow'; +const useThemeProps = createUseThemeProps('MuiTabs'); + const nextItem = (list, item) => { if (list === item) { return list.firstChild; @@ -114,22 +115,30 @@ const TabsRoot = styled('div', { ownerState.vertical && styles.vertical, ]; }, -})(({ ownerState, theme }) => ({ +})(({ theme }) => ({ overflow: 'hidden', minHeight: 48, // Add iOS momentum scrolling for iOS < 13.0 WebkitOverflowScrolling: 'touch', display: 'flex', - ...(ownerState.vertical && { - flexDirection: 'column', - }), - ...(ownerState.scrollButtonsHideMobile && { - [`& .${tabsClasses.scrollButtons}`]: { - [theme.breakpoints.down('sm')]: { - display: 'none', + variants: [ + { + props: ({ ownerState }) => ownerState.vertical, + style: { + flexDirection: 'column', }, }, - }), + { + props: ({ ownerState }) => ownerState.scrollButtonsHideMobile, + style: { + [`& .${tabsClasses.scrollButtons}`]: { + [theme.breakpoints.down('sm')]: { + display: 'none', + }, + }, + }, + }, + ], })); const TabsScroller = styled('div', { @@ -145,31 +154,45 @@ const TabsScroller = styled('div', { ownerState.scrollableY && styles.scrollableY, ]; }, -})(({ ownerState }) => ({ +})({ position: 'relative', display: 'inline-block', flex: '1 1 auto', whiteSpace: 'nowrap', - ...(ownerState.fixed && { - overflowX: 'hidden', - width: '100%', - }), - ...(ownerState.hideScrollbar && { - // Hide dimensionless scrollbar on macOS - scrollbarWidth: 'none', // Firefox - '&::-webkit-scrollbar': { - display: 'none', // Safari + Chrome + variants: [ + { + props: ({ ownerState }) => ownerState.fixed, + style: { + overflowX: 'hidden', + width: '100%', + }, }, - }), - ...(ownerState.scrollableX && { - overflowX: 'auto', - overflowY: 'hidden', - }), - ...(ownerState.scrollableY && { - overflowY: 'auto', - overflowX: 'hidden', - }), -})); + { + props: ({ ownerState }) => ownerState.hideScrollbar, + style: { + // Hide dimensionless scrollbar on macOS + scrollbarWidth: 'none', // Firefox + '&::-webkit-scrollbar': { + display: 'none', // Safari + Chrome + }, + }, + }, + { + props: ({ ownerState }) => ownerState.scrollableX, + style: { + overflowX: 'auto', + overflowY: 'hidden', + }, + }, + { + props: ({ ownerState }) => ownerState.scrollableY, + style: { + overflowY: 'auto', + overflowX: 'hidden', + }, + }, + ], +}); const FlexContainer = styled('div', { name: 'MuiTabs', @@ -182,37 +205,60 @@ const FlexContainer = styled('div', { ownerState.centered && styles.centered, ]; }, -})(({ ownerState }) => ({ +})({ display: 'flex', - ...(ownerState.vertical && { - flexDirection: 'column', - }), - ...(ownerState.centered && { - justifyContent: 'center', - }), -})); + variants: [ + { + props: ({ ownerState }) => ownerState.vertical, + style: { + flexDirection: 'column', + }, + }, + { + props: ({ ownerState }) => ownerState.centered, + style: { + justifyContent: 'center', + }, + }, + ], +}); const TabsIndicator = styled('span', { name: 'MuiTabs', slot: 'Indicator', overridesResolver: (props, styles) => styles.indicator, -})(({ ownerState, theme }) => ({ +})(({ theme }) => ({ position: 'absolute', height: 2, bottom: 0, width: '100%', transition: theme.transitions.create(), - ...(ownerState.indicatorColor === 'primary' && { - backgroundColor: (theme.vars || theme).palette.primary.main, - }), - ...(ownerState.indicatorColor === 'secondary' && { - backgroundColor: (theme.vars || theme).palette.secondary.main, - }), - ...(ownerState.vertical && { - height: '100%', - width: 2, - right: 0, - }), + variants: [ + { + props: { + indicatorColor: 'primary', + }, + style: { + backgroundColor: (theme.vars || theme).palette.primary.main, + }, + }, + { + props: { + indicatorColor: 'secondary', + }, + style: { + backgroundColor: (theme.vars || theme).palette.secondary.main, + }, + }, + { + props: ({ ownerState }) => ownerState.vertical, + style: { + height: '100%', + width: 2, + right: 0, + }, + }, + ], })); const TabsScrollbarSize = styled(ScrollbarSize)({ diff --git a/packages/mui-material/src/TextField/TextField.js b/packages/mui-material/src/TextField/TextField.js index 6e3372513b7aac..244861c33cd277 100644 --- a/packages/mui-material/src/TextField/TextField.js +++ b/packages/mui-material/src/TextField/TextField.js @@ -5,8 +5,7 @@ import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; import useId from '@mui/utils/useId'; import refType from '@mui/utils/refType'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import Input from '../Input'; import FilledInput from '../FilledInput'; import OutlinedInput from '../OutlinedInput'; @@ -16,6 +15,8 @@ import FormHelperText from '../FormHelperText'; import Select from '../Select'; import { getTextFieldUtilityClass } from './textFieldClasses'; +const useThemeProps = createUseThemeProps('MuiTextField'); + const variantComponent = { standard: Input, filled: FilledInput, diff --git a/packages/mui-material/src/Toolbar/Toolbar.js b/packages/mui-material/src/Toolbar/Toolbar.js index 2f9d903e189c05..6a9733d2680580 100644 --- a/packages/mui-material/src/Toolbar/Toolbar.js +++ b/packages/mui-material/src/Toolbar/Toolbar.js @@ -3,10 +3,11 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import composeClasses from '@mui/utils/composeClasses'; -import useThemeProps from '../styles/useThemeProps'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import { getToolbarUtilityClass } from './toolbarClasses'; +const useThemeProps = createUseThemeProps('MuiToolbar'); + const useUtilityClasses = (ownerState) => { const { classes, disableGutters, variant } = ownerState; @@ -25,44 +26,38 @@ const ToolbarRoot = styled('div', { return [styles.root, !ownerState.disableGutters && styles.gutters, styles[ownerState.variant]]; }, -})( - ({ theme }) => ({ - position: 'relative', - display: 'flex', - alignItems: 'center', - variants: [ - { - props: ({ ownerState }) => !ownerState.disableGutters, - style: { - paddingLeft: theme.spacing(2), - paddingRight: theme.spacing(2), - [theme.breakpoints.up('sm')]: { - paddingLeft: theme.spacing(3), - paddingRight: theme.spacing(3), - }, +})(({ theme }) => ({ + position: 'relative', + display: 'flex', + alignItems: 'center', + variants: [ + { + props: ({ ownerState }) => !ownerState.disableGutters, + style: { + paddingLeft: theme.spacing(2), + paddingRight: theme.spacing(2), + [theme.breakpoints.up('sm')]: { + paddingLeft: theme.spacing(3), + paddingRight: theme.spacing(3), }, }, - { - props: { - variant: 'dense', - }, - style: { - minHeight: 48, - }, + }, + { + props: { + variant: 'dense', }, - ], - }), - ({ theme }) => ({ - variants: [ - { - props: { - variant: 'regular', - }, - style: theme.mixins.toolbar, + style: { + minHeight: 48, + }, + }, + { + props: { + variant: 'regular', }, - ], - }), -); + style: theme.mixins.toolbar, + }, + ], +})); const Toolbar = React.forwardRef(function Toolbar(inProps, ref) { const props = useThemeProps({ props: inProps, name: 'MuiToolbar' }); diff --git a/packages/mui-material/src/Tooltip/Tooltip.js b/packages/mui-material/src/Tooltip/Tooltip.js index dc71ddee0481ff..5bfe05f2d1e25e 100644 --- a/packages/mui-material/src/Tooltip/Tooltip.js +++ b/packages/mui-material/src/Tooltip/Tooltip.js @@ -8,9 +8,8 @@ import { appendOwnerState } from '@mui/base/utils'; import composeClasses from '@mui/utils/composeClasses'; import { alpha } from '@mui/system/colorManipulator'; import { useRtl } from '@mui/system/RtlProvider'; -import styled from '../styles/styled'; +import { styled, createUseThemeProps } from '../zero-styled'; import useTheme from '../styles/useTheme'; -import useThemeProps from '../styles/useThemeProps'; import capitalize from '../utils/capitalize'; import Grow from '../Grow'; import Popper from '../Popper'; @@ -21,6 +20,8 @@ import useIsFocusVisible from '../utils/useIsFocusVisible'; import useControlled from '../utils/useControlled'; import tooltipClasses, { getTooltipUtilityClass } from './tooltipClasses'; +const useThemeProps = createUseThemeProps('MuiTooltip'); + function round(value) { return Math.round(value * 1e5) / 1e5; } @@ -55,57 +56,92 @@ const TooltipPopper = styled(Popper, { !ownerState.open && styles.popperClose, ]; }, -})(({ theme, ownerState, open }) => ({ +})(({ theme }) => ({ zIndex: (theme.vars || theme).zIndex.tooltip, pointerEvents: 'none', - ...(!ownerState.disableInteractive && { - pointerEvents: 'auto', - }), - ...(!open && { - pointerEvents: 'none', - }), - ...(ownerState.arrow && { - [`&[data-popper-placement*="bottom"] .${tooltipClasses.arrow}`]: { - top: 0, - marginTop: '-0.71em', - '&::before': { - transformOrigin: '0 100%', + variants: [ + { + props: ({ ownerState }) => !ownerState.disableInteractive, + style: { + pointerEvents: 'auto', }, }, - [`&[data-popper-placement*="top"] .${tooltipClasses.arrow}`]: { - bottom: 0, - marginBottom: '-0.71em', - '&::before': { - transformOrigin: '100% 0', + { + props: ({ open }) => !open, + style: { + pointerEvents: 'none', }, }, - [`&[data-popper-placement*="right"] .${tooltipClasses.arrow}`]: { - ...(!ownerState.isRtl - ? { - left: 0, - marginLeft: '-0.71em', - } - : { - right: 0, - marginRight: '-0.71em', - }), - height: '1em', - width: '0.71em', - '&::before': { - transformOrigin: '100% 100%', + { + props: ({ ownerState }) => ownerState.arrow, + style: { + [`&[data-popper-placement*="bottom"] .${tooltipClasses.arrow}`]: { + top: 0, + marginTop: '-0.71em', + '&::before': { + transformOrigin: '0 100%', + }, + }, + [`&[data-popper-placement*="top"] .${tooltipClasses.arrow}`]: { + bottom: 0, + marginBottom: '-0.71em', + '&::before': { + transformOrigin: '100% 0', + }, + }, + [`&[data-popper-placement*="right"] .${tooltipClasses.arrow}`]: { + height: '1em', + width: '0.71em', + '&::before': { + transformOrigin: '100% 100%', + }, + }, + [`&[data-popper-placement*="left"] .${tooltipClasses.arrow}`]: { + height: '1em', + width: '0.71em', + '&::before': { + transformOrigin: '0 0', + }, + }, }, }, - [`&[data-popper-placement*="left"] .${tooltipClasses.arrow}`]: { - ...(!ownerState.isRtl - ? { right: 0, marginRight: '-0.71em' } - : { left: 0, marginLeft: '-0.71em' }), - height: '1em', - width: '0.71em', - '&::before': { - transformOrigin: '0 0', + { + props: ({ ownerState }) => ownerState.arrow && !ownerState.isRtl, + style: { + [`&[data-popper-placement*="right"] .${tooltipClasses.arrow}`]: { + left: 0, + marginLeft: '-0.71em', + }, }, }, - }), + { + props: ({ ownerState }) => ownerState.arrow && !!ownerState.isRtl, + style: { + [`&[data-popper-placement*="right"] .${tooltipClasses.arrow}`]: { + right: 0, + marginRight: '-0.71em', + }, + }, + }, + { + props: ({ ownerState }) => ownerState.arrow && !ownerState.isRtl, + style: { + [`&[data-popper-placement*="left"] .${tooltipClasses.arrow}`]: { + right: 0, + marginRight: '-0.71em', + }, + }, + }, + { + props: ({ ownerState }) => ownerState.arrow && !!ownerState.isRtl, + style: { + [`&[data-popper-placement*="left"] .${tooltipClasses.arrow}`]: { + left: 0, + marginLeft: '-0.71em', + }, + }, + }, + ], })); const TooltipTooltip = styled('div', { @@ -121,7 +157,7 @@ const TooltipTooltip = styled('div', { styles[`tooltipPlacement${capitalize(ownerState.placement.split('-')[0])}`], ]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ backgroundColor: theme.vars ? theme.vars.palette.Tooltip.bg : alpha(theme.palette.grey[700], 0.92), @@ -134,62 +170,98 @@ const TooltipTooltip = styled('div', { margin: 2, wordWrap: 'break-word', fontWeight: theme.typography.fontWeightMedium, - ...(ownerState.arrow && { - position: 'relative', - margin: 0, - }), - ...(ownerState.touch && { - padding: '8px 16px', - fontSize: theme.typography.pxToRem(14), - lineHeight: `${round(16 / 14)}em`, - fontWeight: theme.typography.fontWeightRegular, - }), [`.${tooltipClasses.popper}[data-popper-placement*="left"] &`]: { transformOrigin: 'right center', - ...(!ownerState.isRtl - ? { - marginRight: '14px', - ...(ownerState.touch && { - marginRight: '24px', - }), - } - : { - marginLeft: '14px', - ...(ownerState.touch && { - marginLeft: '24px', - }), - }), }, [`.${tooltipClasses.popper}[data-popper-placement*="right"] &`]: { transformOrigin: 'left center', - ...(!ownerState.isRtl - ? { - marginLeft: '14px', - ...(ownerState.touch && { - marginLeft: '24px', - }), - } - : { - marginRight: '14px', - ...(ownerState.touch && { - marginRight: '24px', - }), - }), }, [`.${tooltipClasses.popper}[data-popper-placement*="top"] &`]: { transformOrigin: 'center bottom', marginBottom: '14px', - ...(ownerState.touch && { - marginBottom: '24px', - }), }, [`.${tooltipClasses.popper}[data-popper-placement*="bottom"] &`]: { transformOrigin: 'center top', marginTop: '14px', - ...(ownerState.touch && { - marginTop: '24px', - }), }, + variants: [ + { + props: ({ ownerState }) => ownerState.arrow, + style: { + position: 'relative', + margin: 0, + }, + }, + { + props: ({ ownerState }) => ownerState.touch, + style: { + padding: '8px 16px', + fontSize: theme.typography.pxToRem(14), + lineHeight: `${round(16 / 14)}em`, + fontWeight: theme.typography.fontWeightRegular, + }, + }, + { + props: ({ ownerState }) => !ownerState.isRtl, + style: { + [`.${tooltipClasses.popper}[data-popper-placement*="left"] &`]: { + marginRight: '14px', + }, + [`.${tooltipClasses.popper}[data-popper-placement*="right"] &`]: { + marginLeft: '14px', + }, + }, + }, + { + props: ({ ownerState }) => !ownerState.isRtl && ownerState.touch, + style: { + [`.${tooltipClasses.popper}[data-popper-placement*="left"] &`]: { + marginRight: '24px', + }, + [`.${tooltipClasses.popper}[data-popper-placement*="right"] &`]: { + marginLeft: '24px', + }, + }, + }, + { + props: ({ ownerState }) => !!ownerState.isRtl, + style: { + [`.${tooltipClasses.popper}[data-popper-placement*="left"] &`]: { + marginLeft: '14px', + }, + [`.${tooltipClasses.popper}[data-popper-placement*="right"] &`]: { + marginRight: '14px', + }, + }, + }, + { + props: ({ ownerState }) => !!ownerState.isRtl && ownerState.touch, + style: { + [`.${tooltipClasses.popper}[data-popper-placement*="left"] &`]: { + marginLeft: '24px', + }, + [`.${tooltipClasses.popper}[data-popper-placement*="right"] &`]: { + marginRight: '24px', + }, + }, + }, + { + props: ({ ownerState }) => ownerState.touch, + style: { + [`.${tooltipClasses.popper}[data-popper-placement*="top"] &`]: { + marginBottom: '24px', + }, + }, + }, + { + props: ({ ownerState }) => ownerState.touch, + style: { + [`.${tooltipClasses.popper}[data-popper-placement*="bottom"] &`]: { + marginTop: '24px', + }, + }, + }, + ], })); const TooltipArrow = styled('span', { diff --git a/packages/mui-material/src/Typography/Typography.js b/packages/mui-material/src/Typography/Typography.js index 45c555a0e104fe..2e1420999641d2 100644 --- a/packages/mui-material/src/Typography/Typography.js +++ b/packages/mui-material/src/Typography/Typography.js @@ -4,11 +4,12 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import { extendSxProp } from '@mui/system/styleFunctionSx'; import composeClasses from '@mui/utils/composeClasses'; -import styled from '../styles/styled'; -import useThemeProps from '../styles/useThemeProps'; +import { styled, createUseThemeProps } from '../zero-styled'; import capitalize from '../utils/capitalize'; import { getTypographyUtilityClass } from './typographyClasses'; +const useThemeProps = createUseThemeProps('MuiTypography'); + const useUtilityClasses = (ownerState) => { const { align, gutterBottom, noWrap, paragraph, variant, classes } = ownerState; @@ -41,29 +42,61 @@ export const TypographyRoot = styled('span', { ownerState.paragraph && styles.paragraph, ]; }, -})(({ theme, ownerState }) => ({ +})(({ theme }) => ({ margin: 0, - ...(ownerState.variant === 'inherit' && { - // Some elements, like