Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[material-ui][AvatarGroup] deprecate componentsProps for v6 #42122

Merged
merged 23 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
97dbf29
deprecate componentsProps prop
lhilgert9 May 4, 2024
1f4d3d1
add codemod
lhilgert9 May 4, 2024
63f3ea4
add docs for deprecation
lhilgert9 May 4, 2024
288c58b
fix undefined type error
lhilgert9 May 4, 2024
9174052
migrate avatar group tests to not use deprecated apis
lhilgert9 May 4, 2024
8b95211
Revert "migrate avatar group tests to not use deprecated apis"
lhilgert9 May 7, 2024
39c3f40
fix branch on migrate-from-deprecated-apis
lhilgert9 May 8, 2024
309d58b
Merge remote-tracking branch 'upstream/next' into deprecate-avatarGro…
lhilgert9 May 8, 2024
596cd4a
fix missing npx statement
lhilgert9 May 9, 2024
378858a
fix deprecation warning
lhilgert9 May 9, 2024
c997f46
pnpm proptypes
lhilgert9 May 9, 2024
5737aed
implement surplus slots and slotProps
lhilgert9 May 9, 2024
7b3d31a
fix ownerState of surplus that background-color is set
lhilgert9 May 10, 2024
30184a0
improve ownerState fix
lhilgert9 May 10, 2024
7d0c9fd
deprecate additionalAvatar in favor of surplus slotProp and add to co…
lhilgert9 May 12, 2024
1ba9d58
update docs
lhilgert9 May 12, 2024
4ea5878
add comments to codemod
lhilgert9 May 14, 2024
de5c77b
fix surplus slotProps type
lhilgert9 May 14, 2024
fff3076
add tests for new slots and slotProps props
lhilgert9 May 14, 2024
88703af
pnpm prettier
lhilgert9 May 14, 2024
5c395e1
fix surplus ownerState propagation
lhilgert9 May 15, 2024
e8a1512
pnpm prettier
lhilgert9 May 15, 2024
a4fdeb4
Merge remote-tracking branch 'upstream/next' into deprecate-avatarGro…
lhilgert9 May 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,64 @@ The Avatar's `imgProps` prop was deprecated in favor of `slotProps.img`:
/>;
```

## AvatarGroup

Use the [codemod](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#avatar-group-props) below to migrate the code as described in the following sections:

```bash
npx @mui/codemod@next deprecations/avatar-group-props <path>
```

### slotProps.additionalAvatar

The AvatarGroup's `slotProps.additionalAvatar` was deprecated in favor of `slotProps.surplus`:

```diff
<AvatarGroup
slotProps={{
- additionalAvatar: {color: "red"}
+ surplus: {color: "red"}
}}
/>;
```

```diff
MuiAvatarGroup: {
defaultProps: {
slotProps: {
- additionalAvatar: {color: "red"}
+ surplus: {color: "red"}
},
},
},
```

### componentsProps

The AvatarGroup's `componentsProps` was deprecated in favor of `slotProps`:

```diff
<AvatarGroup
- componentsProps={{
- additionalAvatar: {color: "red"}
+ slotProps={{
+ surplus: {color: "red"}
}}
/>;
```

```diff
MuiAvatarGroup: {
defaultProps: {
- componentsProps: {
- additionalAvatar: {color: "red"}
+ slotProps: {
+ surplus: {color: "red"}
},
},
},
```

## Backdrop

Use the [codemod](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#backdrop-props) below to migrate the code as described in the following sections:
Expand Down
14 changes: 11 additions & 3 deletions docs/pages/material-ui/api/avatar-group.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"component": { "type": { "name": "elementType" } },
"componentsProps": {
"type": { "name": "shape", "description": "{ additionalAvatar?: object }" },
"default": "{}"
"deprecated": true,
"deprecationInfo": "use the <code>slotProps</code> prop instead. This prop will be removed in v7. See <a href=\"/material-ui/migration/migrating-from-deprecated-apis/\">Migrating from deprecated APIs</a> for more details."
},
"max": { "type": { "name": "custom", "description": "number" }, "default": "5" },
"renderSurplus": {
Expand All @@ -17,7 +18,14 @@
}
},
"slotProps": {
"type": { "name": "shape", "description": "{ additionalAvatar?: object }" },
"type": {
"name": "shape",
"description": "{ additionalAvatar?: object, surplus?: func<br>&#124;&nbsp;object }"
},
"default": "{}"
},
"slots": {
"type": { "name": "shape", "description": "{ surplus?: elementType }" },
"default": "{}"
},
"spacing": {
Expand Down Expand Up @@ -48,6 +56,7 @@
"import AvatarGroup from '@mui/material/AvatarGroup';",
"import { AvatarGroup } from '@mui/material';"
],
"slots": [{ "name": "surplus", "description": "", "class": null }],
"classes": [
{
"key": "avatar",
Expand All @@ -65,7 +74,6 @@
"spread": true,
"themeDefaultProps": true,
"muiName": "MuiAvatarGroup",
"forwardsRefTo": "HTMLDivElement",
"filename": "/packages/mui-material/src/AvatarGroup/AvatarGroup.js",
"inheritance": null,
"demos": "<ul><li><a href=\"/material-ui/react-avatar/\">Avatar</a></li></ul>",
Expand Down
10 changes: 5 additions & 5 deletions docs/translations/api-docs/avatar-group/avatar-group.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"description": "The component used for the root node. Either a string to use a HTML element or a component."
},
"componentsProps": {
"description": "The extra props for the slot components. You can override the existing props or add new ones.<br>This prop is an alias for the <code>slotProps</code> prop. It&#39;s recommended to use the <code>slotProps</code> prop instead, as <code>componentsProps</code> will be deprecated in the future."
"description": "The extra props for the slot components. You can override the existing props or add new ones.<br>This prop is an alias for the <code>slotProps</code> prop."
},
"max": { "description": "Max avatars to show before +x." },
"renderSurplus": {
Expand All @@ -17,9 +17,8 @@
"React.ReactNode": "custom element to display"
}
},
"slotProps": {
"description": "The extra props for the slot components. You can override the existing props or add new ones.<br>This prop is an alias for the <code>componentsProps</code> prop, which will be deprecated in the future."
},
"slotProps": { "description": "The props used for each slot inside." },
"slots": { "description": "The components used for each slot inside." },
"spacing": { "description": "Spacing between avatars." },
"sx": {
"description": "The system prop that allows defining system overrides as well as additional CSS styles."
Expand All @@ -35,5 +34,6 @@
"nodeName": "the avatar elements"
},
"root": { "description": "Styles applied to the root element." }
}
},
"slotDescriptions": { "surplus": "" }
}
48 changes: 48 additions & 0 deletions packages/mui-codemod/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,54 @@ npx @mui/codemod@next deprecations/alert-props <path>
npx @mui/codemod@next deprecations/autocomplete-props <path>
```

#### `avatar-group-props`

```diff
<AvatarGroup
- componentsProps={{
- additionalAvatar: {color: "red"}
+ slotProps={{
+ surplus: {color: "red"}
}}
/>;
```

```diff
<AvatarGroup
slotProps={{
- additionalAvatar: {color: "red"}
+ surplus: {color: "red"}
}}
/>;
```

lhilgert9 marked this conversation as resolved.
Show resolved Hide resolved
```diff
MuiAvatarGroup: {
defaultProps: {
- componentsProps: {
- additionalAvatar: {color: "red"}
+ slotProps: {
+ surplus: {color: "red"}
},
},
},
```

```diff
MuiAvatarGroup: {
defaultProps: {
slotProps: {
- additionalAvatar: {color: "red"}
+ surplus: {color: "red"}
},
},
},
```

```bash
npx @mui/codemod@next deprecations/avatar-group-props <path>
```

#### `avatar-props`

```diff
Expand Down
2 changes: 2 additions & 0 deletions packages/mui-codemod/src/deprecations/all/deprecations-all.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import transformAccordionProps from '../accordion-props';
import transformAutocompleteProps from '../autocomplete-props';
import transformFormControlLabelProps from '../form-control-label-props';
import transformAvatarGroupProps from '../avatar-group-props';
import transformAvatarProps from '../avatar-props';
import transformDividerProps from '../divider-props';
import transformAccordionClasses from '../accordion-summary-classes';
Expand All @@ -26,6 +27,7 @@ export default function deprecationsAll(file, api, options) {
file.source = transformAccordionProps(file, api, options);
file.source = transformAutocompleteProps(file, api, options);
file.source = transformFormControlLabelProps(file, api, options);
file.source = transformAvatarGroupProps(file, api, options);
file.source = transformAvatarProps(file, api, options);
file.source = transformDividerProps(file, api, options);
file.source = transformAccordionClasses(file, api, options);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import assignObject from '../../util/assignObject';
import findComponentJSX from '../../util/findComponentJSX';
import replaceComponentsWithSlots from '../utils/replaceComponentsWithSlots';

/**
* @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;

replaceComponentsWithSlots(j, { root, componentName: 'AvatarGroup' });

// replace `slotProps.additionalAvatar` with `slotProps.surplus` in JSX
findComponentJSX(j, { root, componentName: 'AvatarGroup' }, (elementPath) => {
lhilgert9 marked this conversation as resolved.
Show resolved Hide resolved
const slotPropsIndex = elementPath.node.openingElement.attributes.findIndex(
(attr) => attr.type === 'JSXAttribute' && attr.name.name === 'slotProps',
);
if (slotPropsIndex !== -1) {
const slotProps = elementPath.node.openingElement.attributes[slotPropsIndex].value.expression;
const additionalAvatarIndex = slotProps.properties.findIndex(
(prop) => prop?.key?.name === 'additionalAvatar',
);
if (additionalAvatarIndex !== -1) {
const surplusIndex = slotProps.properties.findIndex(
(prop) => prop?.key?.name === 'surplus',
);
const removedValue = slotProps.properties.splice(additionalAvatarIndex, 1)[0].value;
if (surplusIndex === -1) {
assignObject(j, {
target: elementPath.node.openingElement.attributes[slotPropsIndex],
key: 'surplus',
expression: removedValue,
});
} else {
const slotPropsSlotValue = slotProps.properties.splice(surplusIndex, 1)[0].value;
assignObject(j, {
target: elementPath.node.openingElement.attributes[slotPropsIndex],
key: 'surplus',
expression: j.objectExpression([
j.spreadElement(removedValue),
j.spreadElement(slotPropsSlotValue),
]),
});
}
}
}
});

// replace `slotProps.additionalAvatar` with `slotProps.surplus` in theme
root.find(j.ObjectProperty, { key: { name: 'MuiAvatarGroup' } }).forEach((path) => {
lhilgert9 marked this conversation as resolved.
Show resolved Hide resolved
const defaultPropsIndex = path.value.value.properties.findIndex(
(key) => key.key.name === 'defaultProps',
);
if (defaultPropsIndex !== -1) {
const defaultProps = path.value.value.properties[defaultPropsIndex];
const slotPropsIndex = defaultProps.value.properties.findIndex(
(prop) => prop.key.name === 'slotProps',
);
if (slotPropsIndex !== -1) {
const slotProps = defaultProps.value.properties[slotPropsIndex];
const additionalAvatarIndex = slotProps.value.properties.findIndex(
(prop) => prop.key.name === 'additionalAvatar',
);
if (additionalAvatarIndex !== -1) {
const removedValue = slotProps.value.properties.splice(additionalAvatarIndex, 1)[0].value;
const surplusIndex = slotProps.value.properties.findIndex(
(prop) => prop.key.name === 'surplus',
);
if (surplusIndex === -1) {
slotProps.value.properties.push(
j.objectProperty(j.identifier('surplus'), removedValue),
);
} else {
const slotPropsSlotValue = slotProps.value.properties.splice(surplusIndex, 1)[0].value;
slotProps.value.properties.push(
j.objectProperty(
j.identifier('surplus'),
j.objectExpression([
j.spreadElement(removedValue),
j.spreadElement(slotPropsSlotValue),
]),
),
);
}
}
}
}
});

return root.toSource(printOptions);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import path from 'path';
import { expect } from 'chai';
import { jscodeshift } from '../../../testUtils';
import transform from './avatar-group-props';
import readFile from '../../util/readFile';

function read(fileName) {
return readFile(path.join(__dirname, fileName));
}

describe('@mui/codemod', () => {
describe('deprecations', () => {
describe('avatar-group-props', () => {
it('transforms props as needed', () => {
const actual = transform({ source: read('./test-cases/actual.js') }, { jscodeshift }, {});

const expected = read('./test-cases/expected.js');
expect(actual).to.equal(expected, 'The transformed version should be correct');
});

it('should be idempotent', () => {
const actual = transform({ 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('[theme] avatar-group-props', () => {
it('transforms props as needed', () => {
const actual = transform(
{ source: read('./test-cases/theme.actual.js') },
{ jscodeshift },
{},
);

const expected = read('./test-cases/theme.expected.js');
expect(actual).to.equal(expected, 'The transformed version should be correct');
});

it('should be idempotent', () => {
const actual = transform(
{ source: read('./test-cases/theme.expected.js') },
{ jscodeshift },
{},
);

const expected = read('./test-cases/theme.expected.js');
expect(actual).to.equal(expected, 'The transformed version should be correct');
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './avatar-group-props';
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import AvatarGroup from '@mui/material/AvatarGroup';
import { AvatarGroup as MyAvatarGroup } from '@mui/material';

<AvatarGroup
componentsProps={{
additionalAvatar: {color: "red"},
}}
/>;
<MyAvatarGroup
componentsProps={{
additionalAvatar: {color: "red"},
}}
/>;
<MyAvatarGroup
componentsProps={{
additionalAvatar: {color: "red"},
}}
slotProps={{
additionalAvatar: {color: "blue"},
}}
/>;
<MyAvatarGroup
componentsProps={{
additionalAvatar: {color: "red"},
}}
slotProps={{
additionalAvatar: {color: "blue"},
surplus: {color: "yellow"},
}}
/>;

// should skip non MUI components
<NonMuiAvatarGroup
componentsProps={{
additionalAvatar: {color: "red"},
}}
/>;