From 1542d1d9606f6fe5951e904f7cf16989da70eb4e Mon Sep 17 00:00:00 2001 From: Diego Andai Date: Fri, 23 Feb 2024 15:47:23 -0300 Subject: [PATCH] [material-ui][Alert] Deprecate composed classes (#40688) --- .../migrating-from-deprecated-apis.md | 95 +++++++++++++++++- docs/pages/material-ui/api/alert.json | 62 +++++++++--- docs/translations/api-docs/alert/alert.json | 58 ++++++++--- packages/mui-codemod/README.md | 96 +++++++++++++++++++ .../alert-classes/alert-classes.js | 80 ++++++++++++++++ .../alert-classes/alert-classes.test.js | 78 +++++++++++++++ .../src/deprecations/alert-classes/index.js | 1 + .../alert-classes/postcss-plugin.js | 39 ++++++++ .../alert-classes/postcss.config.js | 5 + .../alert-classes/test-cases/actual.css | 47 +++++++++ .../alert-classes/test-cases/actual.js | 26 +++++ .../alert-classes/test-cases/expected.css | 47 +++++++++ .../alert-classes/test-cases/expected.js | 26 +++++ .../src/deprecations/all/deprecations-all.js | 2 + .../src/deprecations/all/postcss.config.js | 2 + packages/mui-material/src/Alert/Alert.js | 7 +- packages/mui-material/src/Alert/Alert.test.js | 17 ++++ .../mui-material/src/Alert/alertClasses.ts | 84 +++++++++++++--- 18 files changed, 731 insertions(+), 41 deletions(-) create mode 100644 packages/mui-codemod/src/deprecations/alert-classes/alert-classes.js create mode 100644 packages/mui-codemod/src/deprecations/alert-classes/alert-classes.test.js create mode 100644 packages/mui-codemod/src/deprecations/alert-classes/index.js create mode 100644 packages/mui-codemod/src/deprecations/alert-classes/postcss-plugin.js create mode 100644 packages/mui-codemod/src/deprecations/alert-classes/postcss.config.js create mode 100644 packages/mui-codemod/src/deprecations/alert-classes/test-cases/actual.css create mode 100644 packages/mui-codemod/src/deprecations/alert-classes/test-cases/actual.js create mode 100644 packages/mui-codemod/src/deprecations/alert-classes/test-cases/expected.css create mode 100644 packages/mui-codemod/src/deprecations/alert-classes/test-cases/expected.js diff --git a/docs/data/material/migration/migrating-from-deprecated-apis/migrating-from-deprecated-apis.md b/docs/data/material/migration/migrating-from-deprecated-apis/migrating-from-deprecated-apis.md index 20a214f91e27c9..a6c761d92ddf4b 100644 --- a/docs/data/material/migration/migrating-from-deprecated-apis/migrating-from-deprecated-apis.md +++ b/docs/data/material/migration/migrating-from-deprecated-apis/migrating-from-deprecated-apis.md @@ -92,10 +92,11 @@ Bear in mind that the `.MuiAccordionSummary-gutters` class is applied to the com ## Alert -Use the [codemod](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#alert-props) below to migrate the code as described in the following sections: +Use the [alert-props](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#alert-props) and [alert-classes](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#alert-classes) codemods below to migrate the code as described in the following sections: ```bash npx @mui/codemod@latest deprecations/alert-props +npx @mui/codemod@latest deprecations/alert-classes ``` ### components @@ -120,6 +121,98 @@ The Alert's `componentsProps` was deprecated in favor of `slotProps`: /> ``` +### Composed CSS classes + +The CSS classes that composed the `severity` (or `variant`) and `color` prop values were removed. + +Here's how to migrate: + +```diff +-.MuiAlert-standardSuccess ++.MuiAlert-standard.MuiAlert-colorSuccess +-.MuiAlert-standardInfo ++.MuiAlert-standard.MuiAlert-colorInfo +-.MuiAlert-standardWarning ++.MuiAlert-standard.MuiAlert-colorWarning +-.MuiAlert-standardError ++.MuiAlert-standard.MuiAlert-colorError +-.MuiAlert-outlinedSuccess ++.MuiAlert-outlined.MuiAlert-colorSuccess +-.MuiAlert-outlinedInfo ++.MuiAlert-outlined.MuiAlert-colorInfo +-.MuiAlert-outlinedWarning ++.MuiAlert-outlined.MuiAlert-colorWarning +-.MuiAlert-outlinedError ++.MuiAlert-outlined.MuiAlert-colorError +-.MuiAlert-filledSuccess ++.MuiAlert-filled.MuiAlert-colorSuccess +-.MuiAlert-filledInfo ++.MuiAlert-filled.MuiAlert-colorInfo +-.MuiAlert-filledWarning ++.MuiAlert-filled.MuiAlert-colorWarning +-.MuiAlert-filledError ++.MuiAlert-filled.MuiAlert-colorError +``` + +```diff + import { alertClasses } from '@mui/material/PaginationItem'; + + MuiPaginationItem: { + styleOverrides: { + root: { +- [`&.${alertClasses.standardSuccess}`]: { ++ [`&.${alertClasses.standard}.${alertClasses.colorSuccess}`]: { + color: 'red', + }, +- [`&.${alertClasses.standardInfo}`]: { ++ [`&.${alertClasses.standard}.${alertClasses.colorInfo}`]: { + color: 'red', + }, +- [`&.${alertClasses.standardWarning}`]: { ++ [`&.${alertClasses.standard}.${alertClasses.colorWarning}`]: { + color: 'red', + }, +- [`&.${alertClasses.standardError}`]: { ++ [`&.${alertClasses.standard}.${alertClasses.colorError}`]: { + color: 'red', + }, +- [`&.${alertClasses.outlinedSuccess}`]: { ++ [`&.${alertClasses.outlined}.${alertClasses.colorSuccess}`]: { + color: 'red', + }, +- [`&.${alertClasses.outlinedInfo}`]: { ++ [`&.${alertClasses.outlined}.${alertClasses.colorInfo}`]: { + color: 'red', + }, +- [`&.${alertClasses.outlinedWarning}`]: { ++ [`&.${alertClasses.outlined}.${alertClasses.colorWarning}`]: { + color: 'red', + }, +- [`&.${alertClasses.outlinedError}`]: { ++ [`&.${alertClasses.outlined}.${alertClasses.colorError}`]: { + color: 'red', + }, +- [`&.${alertClasses.filledSuccess}`]: { ++ [`&.${alertClasses.filled}.${alertClasses.colorSuccess}`]: { + color: 'red', + }, +- [`&.${alertClasses.filledInfo}`]: { ++ [`&.${alertClasses.filled}.${alertClasses.colorInfo}`]: { + color: 'red', + }, +- [`&.${alertClasses.filledWarning}`]: { ++ [`&.${alertClasses.filled}.${alertClasses.colorWarning}`]: { + color: 'red', + }, +- [`&.${alertClasses.filledError}`]: { ++ [`&.${alertClasses.filled}.${alertClasses.colorError}`]: { + color: 'red', + }, + }, + }, + }, +``` + ## Avatar Use the [codemod](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#avatar-props) below to migrate the code as described in the following sections: diff --git a/docs/pages/material-ui/api/alert.json b/docs/pages/material-ui/api/alert.json index 6fea5908c00a95..24de72ee0b8fdf 100644 --- a/docs/pages/material-ui/api/alert.json +++ b/docs/pages/material-ui/api/alert.json @@ -99,6 +99,30 @@ "description": "Styles applied to the action wrapper element if `action` is provided.", "isGlobal": false }, + { + "key": "colorError", + "className": "MuiAlert-colorError", + "description": "Styles applied to the root element if `color=\"error\"`.", + "isGlobal": false + }, + { + "key": "colorInfo", + "className": "MuiAlert-colorInfo", + "description": "Styles applied to the root element if `color=\"info\"`.", + "isGlobal": false + }, + { + "key": "colorSuccess", + "className": "MuiAlert-colorSuccess", + "description": "Styles applied to the root element if `color=\"success\"`.", + "isGlobal": false + }, + { + "key": "colorWarning", + "className": "MuiAlert-colorWarning", + "description": "Styles applied to the root element if `color=\"warning\"`.", + "isGlobal": false + }, { "key": "filled", "className": "MuiAlert-filled", @@ -109,25 +133,29 @@ "key": "filledError", "className": "MuiAlert-filledError", "description": "Styles applied to the root element if `variant=\"filled\"` and `color=\"error\"`.", - "isGlobal": false + "isGlobal": false, + "isDeprecated": true }, { "key": "filledInfo", "className": "MuiAlert-filledInfo", "description": "Styles applied to the root element if `variant=\"filled\"` and `color=\"info\"`.", - "isGlobal": false + "isGlobal": false, + "isDeprecated": true }, { "key": "filledSuccess", "className": "MuiAlert-filledSuccess", "description": "Styles applied to the root element if `variant=\"filled\"` and `color=\"success\"`.", - "isGlobal": false + "isGlobal": false, + "isDeprecated": true }, { "key": "filledWarning", "className": "MuiAlert-filledWarning", - "description": "Styles applied to the root element if `variant=\"filled\"` and `color=\"warning\"`.", - "isGlobal": false + "description": "Styles applied to the root element if `variant=\"filled\"` and `color=\"warning\"`", + "isGlobal": false, + "isDeprecated": true }, { "key": "icon", @@ -151,25 +179,29 @@ "key": "outlinedError", "className": "MuiAlert-outlinedError", "description": "Styles applied to the root element if `variant=\"outlined\"` and `color=\"error\"`.", - "isGlobal": false + "isGlobal": false, + "isDeprecated": true }, { "key": "outlinedInfo", "className": "MuiAlert-outlinedInfo", "description": "Styles applied to the root element if `variant=\"outlined\"` and `color=\"info\"`.", - "isGlobal": false + "isGlobal": false, + "isDeprecated": true }, { "key": "outlinedSuccess", "className": "MuiAlert-outlinedSuccess", "description": "Styles applied to the root element if `variant=\"outlined\"` and `color=\"success\"`.", - "isGlobal": false + "isGlobal": false, + "isDeprecated": true }, { "key": "outlinedWarning", "className": "MuiAlert-outlinedWarning", "description": "Styles applied to the root element if `variant=\"outlined\"` and `color=\"warning\"`.", - "isGlobal": false + "isGlobal": false, + "isDeprecated": true }, { "key": "root", @@ -187,25 +219,29 @@ "key": "standardError", "className": "MuiAlert-standardError", "description": "Styles applied to the root element if `variant=\"standard\"` and `color=\"error\"`.", - "isGlobal": false + "isGlobal": false, + "isDeprecated": true }, { "key": "standardInfo", "className": "MuiAlert-standardInfo", "description": "Styles applied to the root element if `variant=\"standard\"` and `color=\"info\"`.", - "isGlobal": false + "isGlobal": false, + "isDeprecated": true }, { "key": "standardSuccess", "className": "MuiAlert-standardSuccess", "description": "Styles applied to the root element if `variant=\"standard\"` and `color=\"success\"`.", - "isGlobal": false + "isGlobal": false, + "isDeprecated": true }, { "key": "standardWarning", "className": "MuiAlert-standardWarning", "description": "Styles applied to the root element if `variant=\"standard\"` and `color=\"warning\"`.", - "isGlobal": false + "isGlobal": false, + "isDeprecated": true } ], "spread": true, diff --git a/docs/translations/api-docs/alert/alert.json b/docs/translations/api-docs/alert/alert.json index a1e17498e79a4b..981d938a884279 100644 --- a/docs/translations/api-docs/alert/alert.json +++ b/docs/translations/api-docs/alert/alert.json @@ -43,6 +43,26 @@ "nodeName": "the action wrapper element", "conditions": "action is provided" }, + "colorError": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "color=\"error\"" + }, + "colorInfo": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "color=\"info\"" + }, + "colorSuccess": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "color=\"success\"" + }, + "colorWarning": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "color=\"warning\"" + }, "filled": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", @@ -51,22 +71,24 @@ "filledError": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", - "conditions": "variant=\"filled\" and color=\"error\"" + "conditions": "variant=\"filled\" and color=\"error\"", + "deprecationInfo": "Combine the .MuiAlert-filled and .MuiAlert-colorError classes instead. How to migrate." }, "filledInfo": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", - "conditions": "variant=\"filled\" and color=\"info\"" + "conditions": "variant=\"filled\" and color=\"info\"", + "deprecationInfo": "Combine the .MuiAlert-filled and .MuiAlert-colorInfo classes instead. How to migrate." }, "filledSuccess": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", - "conditions": "variant=\"filled\" and color=\"success\"" + "conditions": "variant=\"filled\" and color=\"success\"", + "deprecationInfo": "Combine the .MuiAlert-filled and .MuiAlert-colorSuccess classes instead. How to migrate." }, "filledWarning": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"filled\" and color=\"warning\"" + "description": "Styles applied to the root element if variant="filled" and color="warning"", + "deprecationInfo": "Combine the .MuiAlert-filled and .MuiAlert-colorWarning classes instead. How to migrate." }, "icon": { "description": "Styles applied to {{nodeName}}.", @@ -84,22 +106,26 @@ "outlinedError": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", - "conditions": "variant=\"outlined\" and color=\"error\"" + "conditions": "variant=\"outlined\" and color=\"error\"", + "deprecationInfo": "Combine the .MuiAlert-outlined and .MuiAlert-colorError classes instead. How to migrate." }, "outlinedInfo": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", - "conditions": "variant=\"outlined\" and color=\"info\"" + "conditions": "variant=\"outlined\" and color=\"info\"", + "deprecationInfo": "Combine the .MuiAlert-outlined and .MuiAlert-colorInfo classes instead. How to migrate." }, "outlinedSuccess": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", - "conditions": "variant=\"outlined\" and color=\"success\"" + "conditions": "variant=\"outlined\" and color=\"success\"", + "deprecationInfo": "Combine the .MuiAlert-outlined and .MuiAlert-colorSuccess classes instead. How to migrate." }, "outlinedWarning": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", - "conditions": "variant=\"outlined\" and color=\"warning\"" + "conditions": "variant=\"outlined\" and color=\"warning\"", + "deprecationInfo": "Combine the .MuiAlert-outlined and .MuiAlert-colorWarning classes instead. How to migrate." }, "root": { "description": "Styles applied to the root element." }, "standard": { @@ -110,22 +136,26 @@ "standardError": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", - "conditions": "variant=\"standard\" and color=\"error\"" + "conditions": "variant=\"standard\" and color=\"error\"", + "deprecationInfo": "Combine the .MuiAlert-standard and .MuiAlert-colorError classes instead. How to migrate." }, "standardInfo": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", - "conditions": "variant=\"standard\" and color=\"info\"" + "conditions": "variant=\"standard\" and color=\"info\"", + "deprecationInfo": "Combine the .MuiAlert-standard and .MuiAlert-colorInfo classes instead. How to migrate." }, "standardSuccess": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", - "conditions": "variant=\"standard\" and color=\"success\"" + "conditions": "variant=\"standard\" and color=\"success\"", + "deprecationInfo": "Combine the .MuiAlert-standard and .MuiAlert-colorSuccess classes instead. How to migrate." }, "standardWarning": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", - "conditions": "variant=\"standard\" and color=\"warning\"" + "conditions": "variant=\"standard\" and color=\"warning\"", + "deprecationInfo": "Combine the .MuiAlert-standard and .MuiAlert-colorWarning classes instead. How to migrate." } }, "slotDescriptions": { diff --git a/packages/mui-codemod/README.md b/packages/mui-codemod/README.md index e2324924fa15b8..f527a92d273c2c 100644 --- a/packages/mui-codemod/README.md +++ b/packages/mui-codemod/README.md @@ -136,6 +136,102 @@ CSS transforms: npx @mui/codemod@latest deprecations/accordion-summary-classes ``` +#### `alert-classes` + +JS transforms: + +```diff + import { alertClasses } from '@mui/material/PaginationItem'; + + MuiPaginationItem: { + styleOverrides: { + root: { +- [`&.${alertClasses.standardSuccess}`]: { ++ [`&.${alertClasses.standard}.${alertClasses.colorSuccess}`]: { + color: 'red', + }, +- [`&.${alertClasses.standardInfo}`]: { ++ [`&.${alertClasses.standard}.${alertClasses.colorInfo}`]: { + color: 'red', + }, +- [`&.${alertClasses.standardWarning}`]: { ++ [`&.${alertClasses.standard}.${alertClasses.colorWarning}`]: { + color: 'red', + }, +- [`&.${alertClasses.standardError}`]: { ++ [`&.${alertClasses.standard}.${alertClasses.colorError}`]: { + color: 'red', + }, +- [`&.${alertClasses.outlinedSuccess}`]: { ++ [`&.${alertClasses.outlined}.${alertClasses.colorSuccess}`]: { + color: 'red', + }, +- [`&.${alertClasses.outlinedInfo}`]: { ++ [`&.${alertClasses.outlined}.${alertClasses.colorInfo}`]: { + color: 'red', + }, +- [`&.${alertClasses.outlinedWarning}`]: { ++ [`&.${alertClasses.outlined}.${alertClasses.colorWarning}`]: { + color: 'red', + }, +- [`&.${alertClasses.outlinedError}`]: { ++ [`&.${alertClasses.outlined}.${alertClasses.colorError}`]: { + color: 'red', + }, +- [`&.${alertClasses.filledSuccess}`]: { ++ [`&.${alertClasses.filled}.${alertClasses.colorSuccess}`]: { + color: 'red', + }, +- [`&.${alertClasses.filledInfo}`]: { ++ [`&.${alertClasses.filled}.${alertClasses.colorInfo}`]: { + color: 'red', + }, +- [`&.${alertClasses.filledWarning}`]: { ++ [`&.${alertClasses.filled}.${alertClasses.colorWarning}`]: { + color: 'red', + }, +- [`&.${alertClasses.filledError}`]: { ++ [`&.${alertClasses.filled}.${alertClasses.colorError}`]: { + color: 'red', + }, + }, + }, + }, +``` + +CSS transforms: + +```diff +-.MuiAlert-standardSuccess ++.MuiAlert-standard.MuiAlert-colorSuccess +-.MuiAlert-standardInfo ++.MuiAlert-standard.MuiAlert-colorInfo +-.MuiAlert-standardWarning ++.MuiAlert-standard.MuiAlert-colorWarning +-.MuiAlert-standardError ++.MuiAlert-standard.MuiAlert-colorError +-.MuiAlert-outlinedSuccess ++.MuiAlert-outlined.MuiAlert-colorSuccess +-.MuiAlert-outlinedInfo ++.MuiAlert-outlined.MuiAlert-colorInfo +-.MuiAlert-outlinedWarning ++.MuiAlert-outlined.MuiAlert-colorWarning +-.MuiAlert-outlinedError ++.MuiAlert-outlined.MuiAlert-colorError +-.MuiAlert-filledSuccess ++.MuiAlert-filled.MuiAlert-colorSuccess +-.MuiAlert-filledInfo ++.MuiAlert-filled.MuiAlert-colorInfo +-.MuiAlert-filledWarning ++.MuiAlert-filled.MuiAlert-colorWarning +-.MuiAlert-filledError ++.MuiAlert-filled.MuiAlert-colorError +``` + +```bash +npx @mui/codemod@latest deprecations/alert-classes +``` + #### `alert-props` ```diff diff --git a/packages/mui-codemod/src/deprecations/alert-classes/alert-classes.js b/packages/mui-codemod/src/deprecations/alert-classes/alert-classes.js new file mode 100644 index 00000000000000..13c32a4bae1238 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/alert-classes/alert-classes.js @@ -0,0 +1,80 @@ +import { classes } from './postcss-plugin'; + +/** + * @param {import('jscodeshift').FileInfo} file + * @param {import('jscodeshift').API} api + */ +export default function transformer(file, api, options) { + const j = api.jscodeshift; + const root = j(file.source); + const printOptions = options.printOptions; + classes.forEach(({ deprecatedClass, replacementSelector }) => { + root + .find(j.ImportDeclaration) + .filter((path) => path.node.source.value.match(/^@mui\/material\/Alert$/)) + .forEach((path) => { + path.node.specifiers.forEach((specifier) => { + if (specifier.type === 'ImportSpecifier' && specifier.imported.name === 'alertClasses') { + const deprecatedAtomicClass = deprecatedClass.replace('.MuiAlert-', ''); + root + .find(j.MemberExpression, { + object: { name: specifier.local.name }, + property: { name: deprecatedAtomicClass }, + }) + .forEach((memberExpression) => { + const parent = memberExpression.parentPath.parentPath.value; + if (parent.type === j.TemplateLiteral.name) { + const memberExpressionIndex = parent.expressions.findIndex( + (expression) => expression === memberExpression.value, + ); + const precedingTemplateElement = parent.quasis[memberExpressionIndex]; + const atomicClasses = replacementSelector + .replaceAll('MuiAlert-', '') + .split('.') + .filter(Boolean); + + if (precedingTemplateElement.value.raw.endsWith('&.')) { + parent.expressions.splice( + memberExpressionIndex, + 1, + j.memberExpression( + memberExpression.value.object, + j.identifier(atomicClasses[0]), + ), + j.memberExpression( + memberExpression.value.object, + j.identifier(atomicClasses[1]), + ), + ); + parent.quasis.splice( + memberExpressionIndex, + 1, + j.templateElement( + { + raw: precedingTemplateElement.value.raw, + cooked: precedingTemplateElement.value.cooked, + }, + false, + ), + j.templateElement({ raw: '.', cooked: '.' }, false), + ); + } + } + }); + } + }); + }); + + const selectorRegex = new RegExp(`^&${deprecatedClass}`); + + root + .find( + j.Literal, + (literal) => typeof literal.value === 'string' && literal.value.match(selectorRegex), + ) + .forEach((path) => { + path.replace(j.literal(path.value.value.replace(selectorRegex, `&${replacementSelector}`))); + }); + }); + return root.toSource(printOptions); +} diff --git a/packages/mui-codemod/src/deprecations/alert-classes/alert-classes.test.js b/packages/mui-codemod/src/deprecations/alert-classes/alert-classes.test.js new file mode 100644 index 00000000000000..6fcd2044c19d66 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/alert-classes/alert-classes.test.js @@ -0,0 +1,78 @@ +import path from 'path'; +import { expect } from 'chai'; +import postcss from 'postcss'; +import { jscodeshift } from '../../../testUtils'; +import jsTransform from './alert-classes'; +import { plugin as postcssPlugin } from './postcss-plugin'; +import readFile from '../../util/readFile'; + +function read(fileName) { + return readFile(path.join(__dirname, fileName)); +} + +const postcssProcessor = postcss([postcssPlugin]); + +describe('@mui/codemod', () => { + describe('deprecations', () => { + describe('alert-classes', () => { + describe('js-transform', () => { + it('transforms props as needed', () => { + const actual = jsTransform( + { source: read('./test-cases/actual.js') }, + { jscodeshift }, + { printOptions: { quote: 'single', trailingComma: true } }, + ); + + const expected = read('./test-cases/expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + + it('should be idempotent', () => { + const actual = jsTransform( + { source: read('./test-cases/expected.js') }, + { jscodeshift }, + {}, + ); + + const expected = read('./test-cases/expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + }); + + describe('css-transform', () => { + it('transforms classes as needed', async () => { + const actual = await postcssProcessor.process(read('./test-cases/actual.css'), { + from: undefined, + }); + + const expected = read('./test-cases/expected.css'); + expect(actual.css).to.equal(expected, 'The transformed version should be correct'); + }); + + it('should be idempotent', async () => { + const actual = await postcssProcessor.process(read('./test-cases/expected.css'), { + from: undefined, + }); + + const expected = read('./test-cases/expected.css'); + expect(actual.css).to.equal(expected, 'The transformed version should be correct'); + }); + }); + + describe('test-cases', () => { + it('should not be the same', () => { + const actualJS = read('./test-cases/actual.js'); + const expectedJS = read('./test-cases/expected.js'); + expect(actualJS).not.to.equal(expectedJS, 'The actual and expected should be different'); + + const actualCSS = read('./test-cases/actual.css'); + const expectedCSS = read('./test-cases/expected.css'); + expect(actualCSS).not.to.equal( + expectedCSS, + 'The actual and expected should be different', + ); + }); + }); + }); + }); +}); diff --git a/packages/mui-codemod/src/deprecations/alert-classes/index.js b/packages/mui-codemod/src/deprecations/alert-classes/index.js new file mode 100644 index 00000000000000..7193b0b3d350a5 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/alert-classes/index.js @@ -0,0 +1 @@ +export { default } from './alert-classes'; diff --git a/packages/mui-codemod/src/deprecations/alert-classes/postcss-plugin.js b/packages/mui-codemod/src/deprecations/alert-classes/postcss-plugin.js new file mode 100644 index 00000000000000..29995a5ff4a05e --- /dev/null +++ b/packages/mui-codemod/src/deprecations/alert-classes/postcss-plugin.js @@ -0,0 +1,39 @@ +const variants = ['standard', 'outlined', 'filled']; +const colors = ['Success', 'Info', 'Warning', 'Error']; + +const classes = variants.reduce((acc, variant) => { + return acc.concat( + colors.map((color) => { + const deprecatedClass = `.MuiAlert-${variant}${color}`; + const replacementSelector = `.MuiAlert-${variant}.MuiAlert-color${color}`; + + return { + deprecatedClass, + replacementSelector, + }; + }), + ); +}, []); + +const plugin = () => { + return { + postcssPlugin: `Replace deperecated Alert classes with new classes`, + Rule(rule) { + const { selector } = rule; + + classes.forEach(({ deprecatedClass, replacementSelector }) => { + const selectorRegex = new RegExp(`${deprecatedClass}`); + + if (selector.match(selectorRegex)) { + rule.selector = selector.replace(selectorRegex, replacementSelector); + } + }); + }, + }; +}; +plugin.postcss = true; + +module.exports = { + plugin, + classes, +}; diff --git a/packages/mui-codemod/src/deprecations/alert-classes/postcss.config.js b/packages/mui-codemod/src/deprecations/alert-classes/postcss.config.js new file mode 100644 index 00000000000000..23bebc1125be6e --- /dev/null +++ b/packages/mui-codemod/src/deprecations/alert-classes/postcss.config.js @@ -0,0 +1,5 @@ +const { plugin } = require('./postcss-plugin'); + +module.exports = { + plugins: [plugin], +}; diff --git a/packages/mui-codemod/src/deprecations/alert-classes/test-cases/actual.css b/packages/mui-codemod/src/deprecations/alert-classes/test-cases/actual.css new file mode 100644 index 00000000000000..946ca8c6a2cce2 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/alert-classes/test-cases/actual.css @@ -0,0 +1,47 @@ +.MuiAlert-standardSuccess { + color: red; +} + +.MuiAlert-standardInfo { + color: red; +} + +.MuiAlert-standardWarning { + color: red; +} + +.MuiAlert-standardError { + color: red; +} + +.MuiAlert-outlinedSuccess { + color: red; +} + +.MuiAlert-outlinedInfo { + color: red; +} + +.MuiAlert-outlinedWarning { + color: red; +} + +.MuiAlert-outlinedError { + color: red; +} + +.MuiAlert-filledSuccess { + color: red; +} + +.MuiAlert-filledInfo { + color: red; +} + +.MuiAlert-filledWarning { + color: red; +} + +.MuiAlert-filledError { + color: red; +} diff --git a/packages/mui-codemod/src/deprecations/alert-classes/test-cases/actual.js b/packages/mui-codemod/src/deprecations/alert-classes/test-cases/actual.js new file mode 100644 index 00000000000000..93270b52ffa850 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/alert-classes/test-cases/actual.js @@ -0,0 +1,26 @@ +import { alertClasses } from '@mui/material/Alert'; + +('&.MuiAlert-standardSuccess'); +('&.MuiAlert-standardInfo'); +('&.MuiAlert-standardWarning'); +('&.MuiAlert-standardError'); +('&.MuiAlert-outlinedSuccess'); +('&.MuiAlert-outlinedInfo'); +('&.MuiAlert-outlinedWarning'); +('&.MuiAlert-outlinedError'); +('&.MuiAlert-filledSuccess'); +('&.MuiAlert-filledInfo'); +('&.MuiAlert-filledWarning'); +('&.MuiAlert-filledError'); +`&.${alertClasses.standardSuccess}`; +`&.${alertClasses.standardInfo}`; +`&.${alertClasses.standardWarning}`; +`&.${alertClasses.standardError}`; +`&.${alertClasses.outlinedSuccess}`; +`&.${alertClasses.outlinedInfo}`; +`&.${alertClasses.outlinedWarning}`; +`&.${alertClasses.outlinedError}`; +`&.${alertClasses.filledSuccess}`; +`&.${alertClasses.filledInfo}`; +`&.${alertClasses.filledWarning}`; +`&.${alertClasses.filledError}`; diff --git a/packages/mui-codemod/src/deprecations/alert-classes/test-cases/expected.css b/packages/mui-codemod/src/deprecations/alert-classes/test-cases/expected.css new file mode 100644 index 00000000000000..620ef39ea7789c --- /dev/null +++ b/packages/mui-codemod/src/deprecations/alert-classes/test-cases/expected.css @@ -0,0 +1,47 @@ +.MuiAlert-standard.MuiAlert-colorSuccess { + color: red; +} + +.MuiAlert-standard.MuiAlert-colorInfo { + color: red; +} + +.MuiAlert-standard.MuiAlert-colorWarning { + color: red; +} + +.MuiAlert-standard.MuiAlert-colorError { + color: red; +} + +.MuiAlert-outlined.MuiAlert-colorSuccess { + color: red; +} + +.MuiAlert-outlined.MuiAlert-colorInfo { + color: red; +} + +.MuiAlert-outlined.MuiAlert-colorWarning { + color: red; +} + +.MuiAlert-outlined.MuiAlert-colorError { + color: red; +} + +.MuiAlert-filled.MuiAlert-colorSuccess { + color: red; +} + +.MuiAlert-filled.MuiAlert-colorInfo { + color: red; +} + +.MuiAlert-filled.MuiAlert-colorWarning { + color: red; +} + +.MuiAlert-filled.MuiAlert-colorError { + color: red; +} diff --git a/packages/mui-codemod/src/deprecations/alert-classes/test-cases/expected.js b/packages/mui-codemod/src/deprecations/alert-classes/test-cases/expected.js new file mode 100644 index 00000000000000..e55fca0e80f511 --- /dev/null +++ b/packages/mui-codemod/src/deprecations/alert-classes/test-cases/expected.js @@ -0,0 +1,26 @@ +import { alertClasses } from '@mui/material/Alert'; + +('&.MuiAlert-standard.MuiAlert-colorSuccess'); +('&.MuiAlert-standard.MuiAlert-colorInfo'); +('&.MuiAlert-standard.MuiAlert-colorWarning'); +('&.MuiAlert-standard.MuiAlert-colorError'); +('&.MuiAlert-outlined.MuiAlert-colorSuccess'); +('&.MuiAlert-outlined.MuiAlert-colorInfo'); +('&.MuiAlert-outlined.MuiAlert-colorWarning'); +('&.MuiAlert-outlined.MuiAlert-colorError'); +('&.MuiAlert-filled.MuiAlert-colorSuccess'); +('&.MuiAlert-filled.MuiAlert-colorInfo'); +('&.MuiAlert-filled.MuiAlert-colorWarning'); +('&.MuiAlert-filled.MuiAlert-colorError'); +`&.${alertClasses.standard}.${alertClasses.colorSuccess}`; +`&.${alertClasses.standard}.${alertClasses.colorInfo}`; +`&.${alertClasses.standard}.${alertClasses.colorWarning}`; +`&.${alertClasses.standard}.${alertClasses.colorError}`; +`&.${alertClasses.outlined}.${alertClasses.colorSuccess}`; +`&.${alertClasses.outlined}.${alertClasses.colorInfo}`; +`&.${alertClasses.outlined}.${alertClasses.colorWarning}`; +`&.${alertClasses.outlined}.${alertClasses.colorError}`; +`&.${alertClasses.filled}.${alertClasses.colorSuccess}`; +`&.${alertClasses.filled}.${alertClasses.colorInfo}`; +`&.${alertClasses.filled}.${alertClasses.colorWarning}`; +`&.${alertClasses.filled}.${alertClasses.colorError}`; diff --git a/packages/mui-codemod/src/deprecations/all/deprecations-all.js b/packages/mui-codemod/src/deprecations/all/deprecations-all.js index 98d80b66d82115..a360b241125539 100644 --- a/packages/mui-codemod/src/deprecations/all/deprecations-all.js +++ b/packages/mui-codemod/src/deprecations/all/deprecations-all.js @@ -5,6 +5,7 @@ import transformAccordionClasses from '../accordion-summary-classes'; import transformButtonClasses from '../button-classes'; import transformChipClasses from '../chip-classes'; import transformPaginationItemClasses from '../pagination-item-classes'; +import transformAlertClasses from '../alert-classes'; /** * @param {import('jscodeshift').FileInfo} file @@ -18,6 +19,7 @@ export default function deprecationsAll(file, api, options) { file.source = transformButtonClasses(file, api, options); file.source = transformChipClasses(file, api, options); file.source = transformPaginationItemClasses(file, api, options); + file.source = transformAlertClasses(file, api, options); return file.source; } diff --git a/packages/mui-codemod/src/deprecations/all/postcss.config.js b/packages/mui-codemod/src/deprecations/all/postcss.config.js index 9d5a7d81e51e37..9673a34e2131fd 100644 --- a/packages/mui-codemod/src/deprecations/all/postcss.config.js +++ b/packages/mui-codemod/src/deprecations/all/postcss.config.js @@ -1,6 +1,7 @@ const { plugin: accordionSummaryClassesPlugin, } = require('../accordion-summary-classes/postcss-plugin'); +const { plugin: alertClassesPlugin } = require('../alert-classes/postcss-plugin'); const { plugin: buttonClassesPlugin } = require('../button-classes/postcss-plugin'); const { plugin: chipClassesPlugin } = require('../chip-classes/postcss-plugin'); const { @@ -10,6 +11,7 @@ const { module.exports = { plugins: [ accordionSummaryClassesPlugin, + alertClassesPlugin, buttonClassesPlugin, chipClassesPlugin, paginationItemClassesPlugin, diff --git a/packages/mui-material/src/Alert/Alert.js b/packages/mui-material/src/Alert/Alert.js index 9701368cbbf77c..e9d5b3f5a0647b 100644 --- a/packages/mui-material/src/Alert/Alert.js +++ b/packages/mui-material/src/Alert/Alert.js @@ -21,7 +21,12 @@ const useUtilityClasses = (ownerState) => { const { variant, color, severity, classes } = ownerState; const slots = { - root: ['root', `${variant}${capitalize(color || severity)}`, `${variant}`], + root: [ + 'root', + `color${capitalize(color || severity)}`, + `${variant}${capitalize(color || severity)}`, + `${variant}`, + ], icon: ['icon'], message: ['message'], action: ['action'], diff --git a/packages/mui-material/src/Alert/Alert.test.js b/packages/mui-material/src/Alert/Alert.test.js index 18cda2b0690235..e0fefe68874db0 100644 --- a/packages/mui-material/src/Alert/Alert.test.js +++ b/packages/mui-material/src/Alert/Alert.test.js @@ -7,6 +7,7 @@ import Paper, { paperClasses } from '@mui/material/Paper'; import { iconButtonClasses } from '@mui/material/IconButton'; import { svgIconClasses } from '@mui/material/SvgIcon'; import describeConformance from '../../test/describeConformance'; +import capitalize from '../utils/capitalize'; describe('', () => { const { render } = createRenderer(); @@ -198,4 +199,20 @@ describe('', () => { }); }); }); + + describe('classes', () => { + it('should apply default color class to the root', () => { + render(); + + expect(screen.getByTestId('alert')).to.have.class(classes.colorSuccess); + }); + + ['success', 'info', 'warning', 'error'].forEach((color) => { + it('should apply color classes to the root', () => { + render(); + + expect(screen.getByTestId('alert')).to.have.class(classes[`color${capitalize(color)}`]); + }); + }); + }); }); diff --git a/packages/mui-material/src/Alert/alertClasses.ts b/packages/mui-material/src/Alert/alertClasses.ts index f992c041c4e561..e9777b969b9607 100644 --- a/packages/mui-material/src/Alert/alertClasses.ts +++ b/packages/mui-material/src/Alert/alertClasses.ts @@ -10,29 +10,85 @@ export interface AlertClasses { outlined: string; /** Styles applied to the root element if `variant="standard"`. */ standard: string; - /** Styles applied to the root element if `variant="standard"` and `color="success"`. */ + /** Styles applied to the root element if `color="success"`. */ + colorSuccess: string; + /** Styles applied to the root element if `color="info"`. */ + colorInfo: string; + /** Styles applied to the root element if `color="warning"`. */ + colorWarning: string; + /** Styles applied to the root element if `color="error"`. */ + colorError: string; + /** Styles applied to the root element if `variant="standard"` and `color="success"`. + * @deprecated Combine the [.MuiAlert-standard](/material-ui/api/alert/#alert-classes-standard) + * and [.MuiAlert-colorSuccess](/material-ui/api/alert/#alert-classes-colorSuccess) classes instead. + * [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). + */ standardSuccess: string; - /** Styles applied to the root element if `variant="standard"` and `color="info"`. */ + /** Styles applied to the root element if `variant="standard"` and `color="info"`. + * @deprecated Combine the [.MuiAlert-standard](/material-ui/api/alert/#alert-classes-standard) + * and [.MuiAlert-colorInfo](/material-ui/api/alert/#alert-classes-colorInfo) classes instead. + * [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). + */ standardInfo: string; - /** Styles applied to the root element if `variant="standard"` and `color="warning"`. */ + /** Styles applied to the root element if `variant="standard"` and `color="warning"`. + * @deprecated Combine the [.MuiAlert-standard](/material-ui/api/alert/#alert-classes-standard) + * and [.MuiAlert-colorWarning](/material-ui/api/alert/#alert-classes-colorWarning) classes instead. + * [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). + */ standardWarning: string; - /** Styles applied to the root element if `variant="standard"` and `color="error"`. */ + /** Styles applied to the root element if `variant="standard"` and `color="error"`. + * @deprecated Combine the [.MuiAlert-standard](/material-ui/api/alert/#alert-classes-standard) + * and [.MuiAlert-colorError](/material-ui/api/alert/#alert-classes-colorError) classes instead. + * [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). + */ standardError: string; - /** Styles applied to the root element if `variant="outlined"` and `color="success"`. */ + /** Styles applied to the root element if `variant="outlined"` and `color="success"`. + * @deprecated Combine the [.MuiAlert-outlined](/material-ui/api/alert/#alert-classes-outlined) + * and [.MuiAlert-colorSuccess](/material-ui/api/alert/#alert-classes-colorSuccess) classes instead. + * [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). + */ outlinedSuccess: string; - /** Styles applied to the root element if `variant="outlined"` and `color="info"`. */ + /** Styles applied to the root element if `variant="outlined"` and `color="info"`. + * @deprecated Combine the [.MuiAlert-outlined](/material-ui/api/alert/#alert-classes-outlined) + * and [.MuiAlert-colorInfo](/material-ui/api/alert/#alert-classes-colorInfo) classes instead. + * [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). + */ outlinedInfo: string; - /** Styles applied to the root element if `variant="outlined"` and `color="warning"`. */ + /** Styles applied to the root element if `variant="outlined"` and `color="warning"`. + * @deprecated Combine the [.MuiAlert-outlined](/material-ui/api/alert/#alert-classes-outlined) + * and [.MuiAlert-colorWarning](/material-ui/api/alert/#alert-classes-colorWarning) classes instead. + * [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). + */ outlinedWarning: string; - /** Styles applied to the root element if `variant="outlined"` and `color="error"`. */ + /** Styles applied to the root element if `variant="outlined"` and `color="error"`. + * @deprecated Combine the [.MuiAlert-outlined](/material-ui/api/alert/#alert-classes-outlined) + * and [.MuiAlert-colorError](/material-ui/api/alert/#alert-classes-colorError) classes instead. + * [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). + */ outlinedError: string; - /** Styles applied to the root element if `variant="filled"` and `color="success"`. */ + /** Styles applied to the root element if `variant="filled"` and `color="success"`. + * @deprecated Combine the [.MuiAlert-filled](/material-ui/api/alert/#alert-classes-filled) + * and [.MuiAlert-colorSuccess](/material-ui/api/alert/#alert-classes-colorSuccess) classes instead. + * [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). + */ filledSuccess: string; - /** Styles applied to the root element if `variant="filled"` and `color="info"`. */ + /** Styles applied to the root element if `variant="filled"` and `color="info"`. + * @deprecated Combine the [.MuiAlert-filled](/material-ui/api/alert/#alert-classes-filled) + * and [.MuiAlert-colorInfo](/material-ui/api/alert/#alert-classes-colorInfo) classes instead. + * [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). + */ filledInfo: string; - /** Styles applied to the root element if `variant="filled"` and `color="warning"`. */ + /** Styles applied to the root element if `variant="filled"` and `color="warning"` + * @deprecated Combine the [.MuiAlert-filled](/material-ui/api/alert/#alert-classes-filled) + * and [.MuiAlert-colorWarning](/material-ui/api/alert/#alert-classes-colorWarning) classes instead. + * [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). + */ filledWarning: string; - /** Styles applied to the root element if `variant="filled"` and `color="error"`. */ + /** Styles applied to the root element if `variant="filled"` and `color="error"`. + * @deprecated Combine the [.MuiAlert-filled](/material-ui/api/alert/#alert-classes-filled) + * and [.MuiAlert-colorError](/material-ui/api/alert/#alert-classes-colorError) classes instead. + * [How to migrate](/material-ui/migration/migrating-from-deprecated-apis/). + */ filledError: string; /** Styles applied to the icon wrapper element. */ icon: string; @@ -54,6 +110,10 @@ const alertClasses: AlertClasses = generateUtilityClasses('MuiAlert', [ 'icon', 'message', 'filled', + 'colorSuccess', + 'colorInfo', + 'colorWarning', + 'colorError', 'filledSuccess', 'filledInfo', 'filledWarning',