Skip to content

Commit f784dde

Browse files
github-actions[bot]ZeeshanTambolisiriwatknp
authored
[docs][codemod] Add v7 migration docs for deprecated Autocomplete APIs and Autocomplete codemod (@ZeeshanTamboli) (#47954)
Signed-off-by: Zeeshan Tamboli <zeeshan.tamboli@gmail.com> Co-authored-by: Zeeshan Tamboli <zeeshan.tamboli@gmail.com> Co-authored-by: Siriwat K <siriwatkunaporn@gmail.com>
1 parent 95421ba commit f784dde

13 files changed

Lines changed: 315 additions & 2 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Migrating from deprecated APIs
2+
3+
<p class="description">Learn how to migrate away from recently deprecated APIs before they become breaking changes.</p>
4+
5+
## Why you should migrate
6+
7+
Features become deprecated over time as maintainers make improvements to the APIs.
8+
Migrating to these improved APIs results in a better developer experience, so it's in your best interest to stay up to date.
9+
Deprecated APIs often become breaking changes in subsequent major versions, so the sooner you migrate, the smoother the next major update will be.
10+
11+
## Autocomplete
12+
13+
Use the [codemod](https://github.com/mui/material-ui/tree/HEAD/packages/mui-codemod#autocomplete-props) below to migrate the code as described in the following sections:
14+
15+
```bash
16+
npx @mui/codemod@latest deprecations/autocomplete-props <path>
17+
```
18+
19+
### renderTags prop
20+
21+
The `renderTags` prop is deprecated, use `renderValue` instead.
22+
23+
```diff
24+
<Autocomplete
25+
multiple
26+
options={options}
27+
- renderTags={(value, getTagProps, ownerState) =>
28+
- value.map((option, index) => (
29+
- <Chip label={option.label} {...getTagProps({ index })} />
30+
- ))
31+
- }
32+
+ renderValue={(value, getItemProps, ownerState) =>
33+
+ value.map((option, index) => (
34+
+ <Chip label={option.label} {...getItemProps({ index })} />
35+
+ ))
36+
+ }
37+
/>
38+
```
39+
40+
---
41+
42+
### useAutocomplete deprecated fields
43+
44+
The following return value fields are deprecated from the `useAutocomplete` hook:
45+
46+
- `getTagProps` → use `getItemProps`
47+
- `focusedTag` → use `focusedItem`
48+
49+
#### getTagProps
50+
51+
```diff
52+
const {
53+
- getTagProps,
54+
+ getItemProps,
55+
} = useAutocomplete(props);
56+
57+
// ...
58+
-<Chip {...getTagProps({ index })} />
59+
+<Chip {...getItemProps({ index })} />
60+
```
61+
62+
#### focusedTag
63+
64+
```diff
65+
const {
66+
- focusedTag,
67+
+ focusedItem,
68+
} = useAutocomplete(props);
69+
```

docs/data/material/migration/upgrade-to-v7/upgrade-to-v7.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,13 @@ Material UI v7 uses `react-is@19`, which changed how React elements are identif
139139
If you're on React 18 or below, mismatched versions of `react-is` can cause runtime errors in prop type checks.
140140
Forcing `react-is` to match your React version prevents these errors.
141141

142+
## Deprecations
143+
144+
It is not required to immediately go through the deprecations in order to use Material UI v7.
145+
146+
You can do it at your own pace by checking out the [deprecations page](/material-ui/migration/v7/migrating-from-deprecated-apis/).
147+
Those deprecations will be removed in the next major version.
148+
142149
## Breaking changes
143150

144151
Since v7 is a new major release, it contains some changes that affect the public API.

docs/data/material/pages.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,10 @@ const pages: MuiPage[] = [
317317
pathname: '/material-ui/migration/upgrade-to-v7',
318318
title: 'Upgrade to v7: getting started',
319319
},
320+
{
321+
pathname: '/material-ui/migration/v7/migrating-from-deprecated-apis',
322+
title: 'Migrating from deprecated APIs',
323+
},
320324
{
321325
pathname: '/material-ui/migration/upgrade-to-native-color',
322326
title: 'Native color',
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs';
2+
import * as pageProps from 'docs/data/material/migration/upgrade-to-v7/migrating-from-deprecated-apis.md?muiMarkdown';
3+
4+
export default function Page() {
5+
return <MarkdownDocs {...pageProps} />;
6+
}

docs/translations/translations.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@
177177
"/material-ui/migration/pickers-migration": "Migration from @material-ui/pickers",
178178
"Upgrade to v7": "Upgrade to v7",
179179
"/material-ui/migration/upgrade-to-v7": "Upgrade to v7: getting started",
180+
"/material-ui/migration/v7/migrating-from-deprecated-apis": "Migrating from deprecated APIs",
180181
"/material-ui/migration/upgrade-to-native-color": "Native color",
181182
"Upgrade to v6": "Upgrade to v6",
182183
"/material-ui/migration/upgrade-to-v6": "Upgrade to v6: getting started",

packages/mui-codemod/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,11 @@ npx @mui/codemod@latest deprecations/alert-props <path>
278278
- PopperComponent={CustomPopper}
279279
- ListboxComponent={CustomListbox}
280280
- ListboxProps={{ height: 12 }}
281+
- renderTags={(value, getTagProps, ownerState) =>
282+
- value.map((option, index) => (
283+
- <Chip label={option.label} {...getTagProps({ index })} />
284+
- ))
285+
- }
281286
- componentsProps={{
282287
- clearIndicator: { width: 10 },
283288
- paper: { width: 12 },
@@ -299,6 +304,11 @@ npx @mui/codemod@latest deprecations/alert-props <path>
299304
+ popper: { width: 14 },
300305
+ popupIndicator: { width: 16 },
301306
+ }}
307+
+ renderValue={(value, getItemProps, ownerState) =>
308+
+ value.map((option, index) => (
309+
+ <Chip label={option.label} {...getItemProps({ index })} />
310+
+ ))
311+
+ }
302312
/>
303313
```
304314

@@ -310,6 +320,10 @@ npx @mui/codemod@latest deprecations/alert-props <path>
310320
- PopperComponent: CustomPopper,
311321
- ListboxComponent: CustomListbox,
312322
- ListboxProps: { height: 12 },
323+
- renderTags: (value, getTagProps, ownerState) =>
324+
- value.map((option, index) => (
325+
- <Chip label={option.label} {...getTagProps({ index })} />
326+
- )),
313327
- componentsProps: {
314328
- clearIndicator: { width: 10 },
315329
- paper: { width: 12 },
@@ -331,10 +345,23 @@ npx @mui/codemod@latest deprecations/alert-props <path>
331345
+ popper: { width: 14 },
332346
+ popupIndicator: { width: 16 },
333347
+ },
348+
+ renderValue: (value, getItemProps, ownerState) =>
349+
+ value.map((option, index) => (
350+
+ <Chip label={option.label} {...getItemProps({ index })} />
351+
+ )),
334352
},
335353
},
336354
```
337355

356+
```diff
357+
const {
358+
- getTagProps,
359+
- focusedTag,
360+
+ getItemProps,
361+
+ focusedItem,
362+
} = useAutocomplete(props);
363+
```
364+
338365
```bash
339366
npx @mui/codemod@latest deprecations/autocomplete-props <path>
340367
```

packages/mui-codemod/src/deprecations/autocomplete-props/autocomplete-props.js

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,99 @@ import findComponentDefaultProps from '../../util/findComponentDefaultProps';
66
import assignObject from '../../util/assignObject';
77
import appendAttribute from '../../util/appendAttribute';
88

9+
function isNonComputedKey(j, path) {
10+
const parent = path.parent.node;
11+
12+
return (
13+
(j.ObjectProperty.check(parent) || j.Property.check(parent)) &&
14+
parent.key === path.node &&
15+
!parent.computed
16+
);
17+
}
18+
19+
function renameIdentifiersInScope(j, scopePath, oldName, newName) {
20+
const bindingScope = scopePath.scope.lookup(oldName);
21+
22+
if (!bindingScope) {
23+
return;
24+
}
25+
26+
j(bindingScope.path)
27+
.find(j.Identifier, { name: oldName })
28+
.filter((path) => {
29+
if (isNonComputedKey(j, path)) {
30+
return false;
31+
}
32+
33+
return path.scope.lookup(oldName) === bindingScope;
34+
})
35+
.replaceWith(() => j.identifier(newName));
36+
}
37+
38+
function renameRenderTagsCallback(j, callbackPath) {
39+
const getTagPropsParam = callbackPath.node.params[1];
40+
41+
if (getTagPropsParam?.type === 'Identifier' && getTagPropsParam.name === 'getTagProps') {
42+
renameIdentifiersInScope(j, callbackPath, 'getTagProps', 'getItemProps');
43+
}
44+
}
45+
46+
function renameRenderTagsProp(j, propertyPath) {
47+
if (propertyPath.node.key.type === 'Identifier') {
48+
propertyPath.node.key.name = 'renderValue';
49+
}
50+
51+
if (
52+
propertyPath.node.value.type === 'ArrowFunctionExpression' ||
53+
propertyPath.node.value.type === 'FunctionExpression'
54+
) {
55+
renameRenderTagsCallback(j, propertyPath.get('value'));
56+
}
57+
}
58+
59+
function renameUseAutocompleteReturnMembers(j, root) {
60+
const renamedMembers = new Map([
61+
['getTagProps', 'getItemProps'],
62+
['focusedTag', 'focusedItem'],
63+
]);
64+
65+
root
66+
.find(j.VariableDeclarator)
67+
.filter((path) => {
68+
const { id, init } = path.node;
69+
70+
return (
71+
id.type === 'ObjectPattern' &&
72+
init?.type === 'CallExpression' &&
73+
init.callee.type === 'Identifier' &&
74+
init.callee.name === 'useAutocomplete'
75+
);
76+
})
77+
.forEach((path) => {
78+
path.node.id.properties.forEach((property) => {
79+
if (property.type !== 'ObjectProperty' || property.key.type !== 'Identifier') {
80+
return;
81+
}
82+
83+
const nextName = renamedMembers.get(property.key.name);
84+
85+
if (!nextName) {
86+
return;
87+
}
88+
89+
const isShorthand = property.shorthand === true;
90+
const localName = property.value.type === 'Identifier' ? property.value.name : null;
91+
92+
property.key.name = nextName;
93+
94+
if (isShorthand && localName) {
95+
renameIdentifiersInScope(j, path, localName, nextName);
96+
property.shorthand = true;
97+
}
98+
});
99+
});
100+
}
101+
9102
/**
10103
* @param {import('jscodeshift').FileInfo} file
11104
* @param {import('jscodeshift').API} api
@@ -59,6 +152,26 @@ export default function transformer(file, api, options) {
59152
{ root, packageName: options.packageName, componentName: 'Autocomplete' },
60153
(elementPath) => {
61154
const element = elementPath.node;
155+
156+
element.openingElement.attributes.forEach((attribute, index) => {
157+
if (attribute.type !== 'JSXAttribute' || attribute.name.name !== 'renderTags') {
158+
return;
159+
}
160+
161+
attribute.name.name = 'renderValue';
162+
163+
if (
164+
attribute.value?.type === 'JSXExpressionContainer' &&
165+
(attribute.value.expression.type === 'ArrowFunctionExpression' ||
166+
attribute.value.expression.type === 'FunctionExpression')
167+
) {
168+
renameRenderTagsCallback(
169+
j,
170+
elementPath.get('openingElement', 'attributes', index, 'value', 'expression'),
171+
);
172+
}
173+
});
174+
62175
const propIndex = element.openingElement.attributes.findIndex(
63176
(attr) => attr.type === 'JSXAttribute' && attr.name.name === 'ListboxComponent',
64177
);
@@ -169,5 +282,13 @@ export default function transformer(file, api, options) {
169282
path.prune();
170283
});
171284

285+
defaultPropsPathCollection
286+
.find(j.ObjectProperty, { key: { name: 'renderTags' } })
287+
.forEach((path) => {
288+
renameRenderTagsProp(j, path);
289+
});
290+
291+
renameUseAutocompleteReturnMembers(j, root);
292+
172293
return root.toSource(printOptions);
173294
}

packages/mui-codemod/src/deprecations/autocomplete-props/test-cases/actual.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import Autocomplete from '@mui/material/Autocomplete';
22
import {Autocomplete as MyAutocomplete} from '@mui/material';
3+
import Chip from '@mui/material/Chip';
4+
import useAutocomplete from '@mui/material/useAutocomplete';
35

46
<Autocomplete
57
ChipProps={{ height: 10 }}
@@ -61,4 +63,23 @@ import {Autocomplete as MyAutocomplete} from '@mui/material';
6163
PopperComponent={CustomPopper}
6264
ListboxComponent={CustomListbox}
6365
ListboxProps={{ height: 12 }}
64-
/>
66+
/>;
67+
68+
<Autocomplete
69+
multiple
70+
options={options}
71+
renderTags={(value, getTagProps, ownerState) =>
72+
value.map((option, index) => (
73+
<Chip label={option.label} data-focused={ownerState.focused} {...getTagProps({ index })} />
74+
))
75+
}
76+
/>;
77+
78+
const { getTagProps, focusedTag } = useAutocomplete(props);
79+
80+
<Chip {...getTagProps({ index: focusedTag })} />;
81+
82+
const { getTagProps: getAutocompleteTagProps, focusedTag: focusedAutocompleteTag } =
83+
useAutocomplete(props);
84+
85+
<Chip {...getAutocompleteTagProps({ index: focusedAutocompleteTag })} />;

packages/mui-codemod/src/deprecations/autocomplete-props/test-cases/expected.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import Autocomplete from '@mui/material/Autocomplete';
22
import {Autocomplete as MyAutocomplete} from '@mui/material';
3+
import Chip from '@mui/material/Chip';
4+
import useAutocomplete from '@mui/material/useAutocomplete';
35

46
<Autocomplete
57
slots={{
@@ -74,4 +76,23 @@ import {Autocomplete as MyAutocomplete} from '@mui/material';
7476
PopperComponent={CustomPopper}
7577
ListboxComponent={CustomListbox}
7678
ListboxProps={{ height: 12 }}
77-
/>
79+
/>;
80+
81+
<Autocomplete
82+
multiple
83+
options={options}
84+
renderValue={(value, getItemProps, ownerState) =>
85+
value.map((option, index) => (
86+
<Chip label={option.label} data-focused={ownerState.focused} {...getItemProps({ index })} />
87+
))
88+
}
89+
/>;
90+
91+
const { getItemProps, focusedItem } = useAutocomplete(props);
92+
93+
<Chip {...getItemProps({ index: focusedItem })} />;
94+
95+
const { getItemProps: getAutocompleteTagProps, focusedItem: focusedAutocompleteTag } =
96+
useAutocomplete(props);
97+
98+
<Chip {...getAutocompleteTagProps({ index: focusedAutocompleteTag })} />;

packages/mui-codemod/src/deprecations/autocomplete-props/test-cases/package.actual.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Autocomplete from '@org/ui/material/Autocomplete';
22
import {Autocomplete as MyAutocomplete} from '@org/ui/material';
3+
import Chip from '@org/ui/material/Chip';
34

45
<Autocomplete
56
ChipProps={{ height: 10 }}
@@ -61,4 +62,12 @@ import {Autocomplete as MyAutocomplete} from '@org/ui/material';
6162
PopperComponent={CustomPopper}
6263
ListboxComponent={CustomListbox}
6364
ListboxProps={{ height: 12 }}
65+
/>;
66+
67+
<MyAutocomplete
68+
multiple
69+
options={options}
70+
renderTags={(value, getTagProps) =>
71+
value.map((option, index) => <Chip label={option.label} {...getTagProps({ index })} />)
72+
}
6473
/>

0 commit comments

Comments
 (0)