@mui/x-codemod 9.0.0-alpha.4 → 9.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,265 @@
1
1
  # Changelog
2
2
 
3
+ ## 9.0.0-rc.0
4
+
5
+ <!-- generated comparing v9.0.0-beta.0..master -->
6
+
7
+ _Apr 7, 2026_
8
+
9
+ We'd like to extend a big thank you to the 18 contributors who made this release possible.
10
+
11
+ Special thanks go out to these community members for their valuable contributions:
12
+ @mixelburg, @sibananda485, @youjin-hong
13
+
14
+ The following team members contributed to this release:
15
+ @aemartos, @alexfauquette, @arminmeh, @brijeshb42, @flaviendelangle, @JCQuintas, @LukasTy, @mapache-salvaje, @MBilalShafi, @michelengelen, @noraleonte, @rita-codes, @romgrk, @siriwatknp, @ZeeshanTamboli
16
+
17
+ ### Data Grid
18
+
19
+ #### `@mui/x-data-grid@9.0.0-rc.0`
20
+
21
+ - [DataGrid] Rename filter panel `Columns` label to singular `Column` (#21935) @youjin-hong
22
+ - [DataGrid] Export `GridColumnUnsortedIconProps` for custom column icon slots (#21658) @mixelburg
23
+ - [DataGrid] Remove `x-virtualizer`'s `virtualScroller` from public API (#21936) @romgrk
24
+ - [DataGrid][virtualizer] Scrolling without render gaps (#21616) @romgrk
25
+
26
+ #### `@mui/x-data-grid-pro@9.0.0-rc.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
27
+
28
+ Same changes as in `@mui/x-data-grid@9.0.0-rc.0`, plus:
29
+
30
+ - [DataGridPro] Improve trigger for nested row reordering (#21642) @MBilalShafi
31
+ - [DataGridPro] Undeprecate `onRowsScrollEnd` prop (#21912) @MBilalShafi
32
+
33
+ #### `@mui/x-data-grid-premium@9.0.0-rc.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
34
+
35
+ Same changes as in `@mui/x-data-grid-pro@9.0.0-rc.0`, plus:
36
+
37
+ - [DataGridPremium] Fix clipboard paste issue in portal (#21931) @sibananda485
38
+
39
+ ### Date and Time Pickers
40
+
41
+ #### Breaking changes
42
+
43
+ - Accessible DOM structure is now the only default. [Read more](https://next.mui.com/x/migration/migration-pickers-v8/#accessible-dom-structure-is-now-the-default)
44
+ - The `PickerDay2` and `DateRangePickerDay2` components were propagated to stable while removing the previous defaults. [Read more](https://next.mui.com/x/migration/migration-pickers-v8/#day-slot)
45
+
46
+ #### `@mui/x-date-pickers@9.0.0-rc.0`
47
+
48
+ - [pickers] Remove `PickersDay` and `DateRangePickerDay` and promote their `2` versions as replacements (#21739) @michelengelen
49
+
50
+ #### `@mui/x-date-pickers-pro@9.0.0-rc.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
51
+
52
+ Same changes as in `@mui/x-date-pickers@9.0.0-rc.0`.
53
+
54
+ ### Charts
55
+
56
+ #### `@mui/x-charts@9.0.0-rc.0.0`
57
+
58
+ - [charts] Make line visibility toggle start from the baseline (#21893) @alexfauquette
59
+ - [charts] Remove the container overflow (#21955) @alexfauquette
60
+ - [charts] Revert `theme.alpha` for non-channel token (#21965) @siriwatknp
61
+
62
+ #### `@mui/x-charts-pro@9.0.0-rc.0.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
63
+
64
+ Same changes as in `@mui/x-charts@9.0.0-rc.0.0`, plus:
65
+
66
+ - [charts-pro] Zoom slider touch improvements (#21832) @JCQuintas
67
+ - [charts-pro] Add `seriesIds` filter to zoom slider preview (#21933) @JCQuintas
68
+ - [charts-pro] Fix zoom slider preview with discard filter mode (#21883) @JCQuintas
69
+
70
+ #### `@mui/x-charts-premium@9.0.0-rc.0.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
71
+
72
+ Same changes as in `@mui/x-charts-pro@9.0.0-rc.0.0`, plus:
73
+
74
+ - [charts-premium] Add series `valueFormatter` to candlestick chart (#21905) @JCQuintas
75
+ - [charts-premium] Add zoom slider preview support for candlestick charts (#21914) @JCQuintas
76
+ - [charts-premium] Allow color customization in `Candlestick` chart (#21838) @JCQuintas
77
+ - [charts-premium] Support hide/show for OHLC (candlestick) series (#21807) @Copilot
78
+ - [charts-premium] Add `dataset` support to `Candlestick` chart (#21872) @JCQuintas
79
+ - [charts-premium] Add candlestick page to sidebar navigation (#21834) @JCQuintas
80
+
81
+ ### Tree View
82
+
83
+ #### `@mui/x-tree-view@9.0.0-rc.0`
84
+
85
+ Internal changes.
86
+
87
+ #### `@mui/x-tree-view-pro@9.0.0-rc.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
88
+
89
+ Same changes as in `@mui/x-tree-view@9.0.0-rc.0`, plus:
90
+
91
+ - [RichTreeViewPro] Allow to auto-expand lazy loaded items (#21759) @flaviendelangle
92
+
93
+ ### Scheduler
94
+
95
+ #### `@mui/x-scheduler@9.0.0-alpha.0`
96
+
97
+ - [scheduler] Add locale files, adapt l10n scripts, and add localization table to docs (#21870) @rita-codes
98
+ - [scheduler] Add planned features to the docs (#21705) @rita-codes
99
+ - [scheduler] Add scheduler to docs introduction (#21845) @rita-codes
100
+ - [scheduler] Add wide docs to scheduler (#21860) @noraleonte
101
+ - [scheduler] All day event bugfixes (#21884) @noraleonte
102
+ - [scheduler] Autofocus title field (#21947) @noraleonte
103
+ - [scheduler] Change default event creation trigger to single click (#21979) @rita-codes
104
+ - [scheduler] Change order of the views on the view selector (#21904) @rita-codes
105
+ - [scheduler] Disabled border color for the repeat day picker in dark mode (#21987) @rita-codes
106
+ - [scheduler] Drop unused dependency (#21956) @flaviendelangle
107
+ - [scheduler] Fix all-day event shifting to previous day in negative UTC offsets (#21994) @rita-codes
108
+ - [scheduler] Fix dark theme localization demos (#21992) @noraleonte
109
+ - [scheduler] Fix licensing confusion in docs (#21939) @rita-codes
110
+ - [scheduler] Fix preferences menu width shift when toggling options + Improve preferences menu accessibility (#21902) @rita-codes
111
+ - [scheduler] Prepare for the alpha launch (#21859) @rita-codes
112
+ - [scheduler] Sync Base UI internals and apply good practices (#21946) @flaviendelangle
113
+ - [scheduler] Update close modal aria label translation (#21940) @rita-codes
114
+ - [scheduler] Add Spanish (es-ES) locale (#21900) @rita-codes
115
+ - [scheduler] Improve French (fr-FR) locale (#21941) @rita-codes
116
+ - [scheduler] Improve Romanian (ro-RO) locale (#21942) @rita-codes
117
+
118
+ #### `@mui/x-scheduler-premium@9.0.0-alpha.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
119
+
120
+ Same changes as in `@mui/x-scheduler@9.0.0-alpha.0`.
121
+
122
+ ### Codemod
123
+
124
+ #### `@mui/x-codemod@9.0.0-rc.0`
125
+
126
+ Internal changes.
127
+
128
+ ### Docs
129
+
130
+ - [docs] Fix JSDOM → jsdom casing (#21907) @JCQuintas
131
+ - [docs] Remove Joy UI references and dependency (#21937) @siriwatknp
132
+ - [docs] Remove none generated files (#21886) @alexfauquette
133
+ - [docs] Remove unused interactive demo code (#21945) @LukasTy
134
+ - [docs] Revise the Funnel doc (#21677) @mapache-salvaje
135
+ - [docs] Revise the Line chart docs (#21554) @mapache-salvaje
136
+ - [docs] Revise the Radar doc (#21674) @mapache-salvaje
137
+ - [docs] Revise the Sankey doc (#21678) @mapache-salvaje
138
+ - [docs] Revise the Scatter chart docs (#21564) @mapache-salvaje
139
+
140
+ ### Core
141
+
142
+ - [docs-infra] Update to the latest monorepo (#21971) @brijeshb42
143
+ - [internal] Remove checks for `materialVersion >= 6` (#21975) @LukasTy
144
+
145
+ ### Miscellaneous
146
+
147
+ - [core] Bump @mui/material to v9.0.0-beta.1 (#21858) @siriwatknp
148
+ - [core] Update browserslistrc (#21974) @siriwatknp
149
+ - [deps] Bump minimum core packages to 7.3.0 to adopt theme color manipulator (#21892) @siriwatknp
150
+ - [telemetry] Prefer upstream remote over origin for `projectId` (#21882) @aemartos
151
+ - [telemetry] Send `repoHash`, `[x]packageNameHash`, and `rootPathHash` alongside `projectId` (#21896) @aemartos
152
+ - [test] Exclude flaky `DataGrid` argos test (#21977) @MBilalShafi
153
+ - [test] Fix flaky `DataGrid` test (#22000) @arminmeh
154
+ - [test] Remove `componentsProp` test from `describeConformance` (#21897) @ZeeshanTamboli
155
+ - [x-license] Change `orderId` type from `number` to `string` (#21885) @aemartos
156
+
157
+ ## 9.0.0-beta.0
158
+
159
+ <!-- generated comparing v9.0.0-alpha.4..master -->
160
+
161
+ _Mar 27, 2026_
162
+
163
+ We'd like to extend a big thank you to the 10 contributors who made this release possible. Here are some highlights ✨:
164
+
165
+ - 🔊 New Charts voiceover component for improved screen reader support
166
+ - ⌨️ Charts keyboard navigation improvements: axis tooltip now shows when navigating with the keyboard
167
+ - 📊 Charts axes now can be set to automatically resize to fit their content
168
+ - 📝 New `rowCheckbox` slot in Data Grid for easier checkbox column customization
169
+ - ⚡️ `fetchRows()` API in Data Grid Pro now defaults `start` and `end` based on scroll position with lazy loading
170
+ - 🐞 Bugfixes and internal improvements
171
+
172
+ The following team members contributed to this release:
173
+ @aemartos, @alexfauquette, @arminmeh, @cherniavskii, @Janpot, @JCQuintas, @mapache-salvaje, @michelengelen, @noraleonte, @rita-codes
174
+
175
+ ### Data Grid
176
+
177
+ #### `@mui/x-data-grid@9.0.0-beta.0`
178
+
179
+ - [DataGrid] Add `rowCheckbox` slot for easier customization (#21797) @michelengelen
180
+ - [DataGrid] Prevent repeated `hasScrollbar` state updates (#21820) @arminmeh
181
+
182
+ #### `@mui/x-data-grid-pro@9.0.0-beta.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
183
+
184
+ Same changes as in `@mui/x-data-grid@9.0.0-beta.0`, plus:
185
+
186
+ - [DataGridPro] `fetchRows()` API's default `start` and `end` params based on scroll position with lazy loading (#21742) @arminmeh
187
+
188
+ #### `@mui/x-data-grid-premium@9.0.0-beta.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
189
+
190
+ Same changes as in `@mui/x-data-grid-pro@9.0.0-beta.0`.
191
+
192
+ ### Date and Time Pickers
193
+
194
+ #### `@mui/x-date-pickers@9.0.0-beta.0`
195
+
196
+ Internal changes.
197
+
198
+ #### `@mui/x-date-pickers-pro@9.0.0-beta.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
199
+
200
+ Same changes as in `@mui/x-date-pickers@9.0.0-beta.0`.
201
+
202
+ ### Charts
203
+
204
+ #### `@mui/x-charts@9.0.0-beta.0`
205
+
206
+ - [charts] Add `className` prop to Pro chart plot components (#21793) @JCQuintas
207
+ - [charts] Add experimental position-based pointer interaction for line series (#21809) @JCQuintas
208
+ - [charts] Add l10n to the bar accessibility (#21815) @alexfauquette
209
+ - [charts] Add localization for the basic charts (#21822) @alexfauquette
210
+ - [charts] Add voiceover component (#21344) @alexfauquette
211
+ - [charts] Allow axes to automatically resize to content (#21087) @JCQuintas
212
+ - [charts] Document multiple use-cases for references (#21768) @alexfauquette
213
+ - [charts] Remove compatibility layer for React vs native events (#21780) @JCQuintas
214
+ - [charts] Remove deprecated `barLabel` props (#21783) @alexfauquette
215
+ - [charts] Show axis tooltip when navigating with keyboard (#21689) @Copilot
216
+
217
+ #### `@mui/x-charts-pro@9.0.0-beta.0` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
218
+
219
+ Same changes as in `@mui/x-charts@9.0.0-beta.0`.
220
+
221
+ #### `@mui/x-charts-premium@9.0.0-beta.0` [![premium](https://mui.com/r/x-premium-svg)](https://mui.com/r/x-premium-svg-link 'Premium plan')
222
+
223
+ Same changes as in `@mui/x-charts-pro@9.0.0-beta.0`.
224
+
225
+ ### Tree View
226
+
227
+ #### `@mui/x-tree-view@9.0.0-alpha.4`
228
+
229
+ Internal changes.
230
+
231
+ #### `@mui/x-tree-view-pro@9.0.0-alpha.4` [![pro](https://mui.com/r/x-pro-svg)](https://mui.com/r/x-pro-svg-link 'Pro plan')
232
+
233
+ Same changes as in `@mui/x-tree-view@9.0.0-alpha.4`.
234
+
235
+ ### Codemod
236
+
237
+ #### `@mui/x-codemod@9.0.0-alpha.4`
238
+
239
+ Internal changes.
240
+
241
+ ### Docs
242
+
243
+ - [docs] Document how to customize voiceover announcement (#21833) @alexfauquette
244
+ - [docs] Remove Discord mention from docs (#21855) @mapache-salvaje
245
+ - [docs] Remove stabilized experimental feature from demo (#21869) @JCQuintas
246
+ - [docs] Update telemetry guide to reflect pseudonymous data collection and license compliance (#21812) @aemartos
247
+ - [docs] Revise the Sparkline doc (#21614) @mapache-salvaje
248
+ - [docs] Revise the Gauge doc (#21673) @mapache-salvaje
249
+ - [docs] Revise the Heatmap doc (#21676) @mapache-salvaje
250
+
251
+ ### Core
252
+
253
+ - [code-infra] Remove unused deps and unify es-toolkit via catalog (#21840) @Janpot
254
+ - [code-infra] Update @mui/internal-bundle-size-checker to canary.68 (#21836) @Janpot
255
+ - [code-infra] Update next (#21837) @Janpot
256
+ - [internal] Remove headless data grid packages (#21843) @cherniavskii
257
+
258
+ ### Miscellaneous
259
+
260
+ - Add @romgrk to CODEOWNERS for `x-virtualizer` and `x-internals` (#21819) @Copilot
261
+ - [x-license] add 2022 plan version (#21814) @aemartos
262
+
3
263
  ## 9.0.0-alpha.4
4
264
 
5
265
  _Mar 19, 2026_
@@ -59,7 +319,7 @@ Same changes as in `@mui/x-date-pickers@9.0.0-alpha.4`.
59
319
  - [charts] Remove deprecated `useMouseTracker()` (#21787) @alexfauquette
60
320
  - [charts] Remove deprecated classes (#21775) @alexfauquette
61
321
  - [charts] Remove deprecated props from PieArcLabel animation (#21789) @alexfauquette
62
- - [charts] Remove get*UtilityClass from public exports (#21769) @JCQuintas
322
+ - [charts] Remove get\*UtilityClass from public exports (#21769) @JCQuintas
63
323
  - [charts] Remove the deprecated `disableHover` property (#21785) @alexfauquette
64
324
  - [charts] Remove the deprecated `message` prop (#21784) @alexfauquette
65
325
  - [charts] Remove deprecated props about voronoi (#21796) @alexfauquette
@@ -207,7 +467,7 @@ Same changes as in `@mui/x-charts-pro@9.0.0-alpha.3`, plus:
207
467
  - Remove deprecated CSS state classes from `treeItemClasses`: `expanded`, `selected`, `focused`, `disabled`, `editable`, `editing` (use `[data-expanded]`, `[data-selected]`, etc.)
208
468
  - The `<RichTreeViewPro />` component has now virtualization enabled by default.
209
469
  - The items used inside the `<RichTreeViewPro />` now have a default height of `32px`.
210
- - The events of the `<RichTreeViewPro />` are now rendered as a flat list instead of a nested tree.
470
+ - The items of the `<RichTreeViewPro />` are now rendered as a flat list instead of a nested tree.
211
471
 
212
472
  #### `@mui/x-tree-view@9.0.0-alpha.3`
213
473
 
package/README.md CHANGED
@@ -76,9 +76,9 @@ The corresponding sub-sections are listed below
76
76
 
77
77
  <!-- - [`preset-safe-for-tree-view`](#preset-safe-for-tree-view-v900) -->
78
78
  <!-- - [`preset-safe-for-data-grid`](#preset-safe-for-data-grid-v900) -->
79
- <!-- - [`preset-safe-for-pickers`](#preset-safe-for-pickers-v900) -->
80
79
 
81
80
  - [`preset-safe-for-charts`](#preset-safe-for-charts-v900)
81
+ - [`preset-safe-for-pickers`](#preset-safe-for-pickers-v900)
82
82
 
83
83
  ### Data Grid codemods
84
84
 
@@ -311,6 +311,182 @@ Replaces the deprecated `isBarSeries()` and `isDefaultizedBarSeries()` helper fu
311
311
  }
312
312
  ```
313
313
 
314
+ ### Pickers codemods
315
+
316
+ #### 🚀 `preset-safe` for Pickers v9.0.0 <a id="preset-safe-for-pickers-v900"></a>
317
+
318
+ The `preset-safe` codemods for Pickers.
319
+
320
+ <!-- #npm-tag-reference -->
321
+
322
+ ```bash
323
+ npx @mui/x-codemod@next v9.0.0/pickers/preset-safe <path|folder>
324
+ ```
325
+
326
+ The list includes these transformers
327
+
328
+ - [`rename-field-ref`](#rename-field-ref)
329
+ - [`remove-enable-accessible-field-dom-structure`](#remove-enable-accessible-field-dom-structure)
330
+ - [`remove-picker-day-2`](#remove-picker-day-2)
331
+ - [`rename-picker-day-2`](#rename-picker-day-2)
332
+ - [`rename-pickers-day`](#rename-pickers-day)
333
+ - [`rename-picker-classes`](#rename-picker-classes)
334
+ - [`remove-disable-margin`](#remove-disable-margin)
335
+
336
+ #### `rename-field-ref`
337
+
338
+ Renames the `unstableFieldRef` prop to `fieldRef` on all Picker and Field components.
339
+
340
+ ```diff
341
+ -<DateField unstableFieldRef={fieldRef} />
342
+ +<DateField fieldRef={fieldRef} />
343
+
344
+ -<DateRangePicker unstableStartFieldRef={startRef} unstableEndFieldRef={endRef} />
345
+ +<DateRangePicker startFieldRef={startRef} endFieldRef={endRef} />
346
+
347
+ -<DatePicker slotProps={{ field: { unstableFieldRef: fieldRef } }} />
348
+ +<DatePicker slotProps={{ field: { fieldRef: fieldRef } }} />
349
+ ```
350
+
351
+ <!-- #npm-tag-reference -->
352
+
353
+ ```bash
354
+ npx @mui/x-codemod@next v9.0.0/pickers/rename-field-ref <path|folder>
355
+ ```
356
+
357
+ #### `remove-enable-accessible-field-dom-structure`
358
+
359
+ Removes the `enableAccessibleFieldDOMStructure` prop from all Picker and Field components.
360
+ The accessible DOM structure is now the only supported option and this prop has no effect.
361
+
362
+ ```diff
363
+ -<DateField enableAccessibleFieldDOMStructure={false} />
364
+ +<DateField />
365
+
366
+ -<DatePicker enableAccessibleFieldDOMStructure={false} slots={{ textField: MyCustomTextField }} />
367
+ +<DatePicker slots={{ textField: MyCustomTextField }} />
368
+
369
+ -<DatePicker slotProps={{ field: { enableAccessibleFieldDOMStructure: false } }} />
370
+ +<DatePicker />
371
+ ```
372
+
373
+ <!-- #npm-tag-reference -->
374
+
375
+ ```bash
376
+ npx @mui/x-codemod@next v9.0.0/pickers/remove-enable-accessible-field-dom-structure <path|folder>
377
+ ```
378
+
379
+ #### `remove-picker-day-2`
380
+
381
+ Removes the unnecessary `slots={{ day: PickerDay2 }}` and `slots={{ day: DateRangePickerDay2 }}` usages, since `PickerDay2` and `DateRangePickerDay2` are the new defaults.
382
+ Also handles objects passed through variables (for example `const slots = { day: PickerDay2 }`).
383
+
384
+ ```diff
385
+ -<DatePicker slots={{ day: PickerDay2 }} />
386
+ +<DatePicker />
387
+
388
+ -<DateRangePicker slots={{ day: DateRangePickerDay2 }} />
389
+ +<DateRangePicker />
390
+ ```
391
+
392
+ <!-- #npm-tag-reference -->
393
+
394
+ ```bash
395
+ npx @mui/x-codemod@next v9.0.0/pickers/remove-picker-day-2 <path>
396
+ ```
397
+
398
+ #### `rename-picker-day-2`
399
+
400
+ Renames `PickerDay2` and `DateRangePickerDay2` components and their related types, classes, and theme component names to `PickerDay` and `DateRangePickerDay`.
401
+
402
+ ```diff
403
+ -import { PickerDay2, PickerDay2Props, pickerDay2Classes } from '@mui/x-date-pickers/PickerDay2';
404
+ +import { PickerDay, PickerDayProps, pickerDayClasses } from '@mui/x-date-pickers/PickerDay';
405
+
406
+ -import { DateRangePickerDay2 } from '@mui/x-date-pickers-pro/DateRangePickerDay2';
407
+ +import { DateRangePickerDay } from '@mui/x-date-pickers-pro/DateRangePickerDay';
408
+
409
+ const theme = createTheme({
410
+ components: {
411
+ - MuiPickerDay2: {
412
+ + MuiPickerDay: {
413
+ styleOverrides: { root: { color: 'red' } },
414
+ },
415
+ },
416
+ });
417
+ ```
418
+
419
+ <!-- #npm-tag-reference -->
420
+
421
+ ```bash
422
+ npx @mui/x-codemod@next v9.0.0/pickers/rename-picker-day-2 <path>
423
+ ```
424
+
425
+ #### `rename-pickers-day`
426
+
427
+ Renames `PickersDay` to `PickerDay` and all related types, classes, and theme component names.
428
+
429
+ ```diff
430
+ -import { PickersDay, PickersDayProps, pickersDayClasses } from '@mui/x-date-pickers/PickersDay';
431
+ +import { PickerDay, PickerDayProps, pickerDayClasses } from '@mui/x-date-pickers/PickerDay';
432
+
433
+ const theme = createTheme({
434
+ components: {
435
+ - MuiPickersDay: {
436
+ + MuiPickerDay: {
437
+ styleOverrides: { root: { color: 'red' } },
438
+ },
439
+ },
440
+ });
441
+ ```
442
+
443
+ <!-- #npm-tag-reference -->
444
+
445
+ ```bash
446
+ npx @mui/x-codemod@next v9.0.0/pickers/rename-pickers-day <path>
447
+ ```
448
+
449
+ #### `rename-picker-classes`
450
+
451
+ Renames `PickerDay` and `DateRangePickerDay` CSS class keys to their new equivalents.
452
+
453
+ ```diff
454
+ -'& .MuiPickerDay-outsideCurrentMonth'
455
+ +'& .MuiPickerDay-dayOutsideMonth'
456
+
457
+ -'& .MuiDateRangePickerDay-rangeIntervalDayHighlightStart'
458
+ +'& .MuiDateRangePickerDay-selectionStart'
459
+
460
+ -'& .MuiDateRangePickerDay-dayInsideRangeInterval'
461
+ +'& .MuiDateRangePickerDay-insideSelection'
462
+ ```
463
+
464
+ <!-- #npm-tag-reference -->
465
+
466
+ ```bash
467
+ npx @mui/x-codemod@next v9.0.0/pickers/rename-picker-classes <path>
468
+ ```
469
+
470
+ #### `remove-disable-margin`
471
+
472
+ Removes the `disableMargin` prop from `PickerDay` and `DateRangePickerDay` components and replaces it with the `--PickerDay-horizontalMargin` CSS variable via the `sx` prop.
473
+
474
+ ```diff
475
+ -<PickerDay disableMargin day={day} />
476
+ +<PickerDay day={day} sx={{ '--PickerDay-horizontalMargin': 0 }} />
477
+
478
+ -<DatePicker slotProps={{ day: { disableMargin: true } }} />
479
+ +<DatePicker slotProps={{ day: { sx: { '--PickerDay-horizontalMargin': 0 } } }} />
480
+ ```
481
+
482
+ When `disableMargin={false}`, the prop is simply removed without adding the CSS variable.
483
+
484
+ <!-- #npm-tag-reference -->
485
+
486
+ ```bash
487
+ npx @mui/x-codemod@next v9.0.0/pickers/remove-disable-margin <path>
488
+ ```
489
+
314
490
  ## v8.0.0
315
491
 
316
492
  ### 🚀 `preset-safe` for v8.0.0
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@mui/x-codemod",
3
- "version": "9.0.0-alpha.4",
3
+ "version": "9.0.0-rc.0",
4
4
  "author": "MUI Team",
5
5
  "description": "Codemod scripts for MUI X.",
6
+ "license": "MIT",
6
7
  "keywords": [
7
8
  "react",
8
9
  "react-component",
@@ -16,7 +17,6 @@
16
17
  "url": "git+https://github.com/mui/mui-x.git",
17
18
  "directory": "packages/x-codemod"
18
19
  },
19
- "license": "MIT",
20
20
  "homepage": "https://github.com/mui/mui-x/tree/master/packages/x-codemod",
21
21
  "funding": {
22
22
  "type": "opencollective",
@@ -28,7 +28,7 @@
28
28
  "@babel/traverse": "^7.29.0",
29
29
  "jscodeshift": "17.3.0",
30
30
  "yargs": "^18.0.0",
31
- "@mui/x-internals": "9.0.0-alpha.4"
31
+ "@mui/x-internals": "9.0.0-rc.0"
32
32
  },
33
33
  "sideEffects": false,
34
34
  "publishConfig": {
@@ -44,7 +44,14 @@ function renameClasses(parameters) {
44
44
  localNameToOldClassName[hasAlias ? localName : oldName] = oldName;
45
45
  renamedIdentifiersMap[oldName] = config.newClassName;
46
46
  if (!hasAlias && alreadyAvailableIdentifiersMap.has(config.newClassName)) {
47
+ const importDeclarationCollection = j(path).closest(j.ImportDeclaration);
47
48
  path.prune();
49
+ if (importDeclarationCollection.length > 0) {
50
+ const importDeclaration = importDeclarationCollection.nodes()[0];
51
+ if (importDeclaration.specifiers?.length === 0) {
52
+ importDeclarationCollection.remove();
53
+ }
54
+ }
48
55
  return;
49
56
  }
50
57
  alreadyAvailableIdentifiersMap.add(config.newClassName);
@@ -5,10 +5,25 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.default = transformer;
8
+ exports.testConfig = void 0;
8
9
  var _renameFieldRef = _interopRequireDefault(require("../rename-field-ref"));
10
+ var _removePickerDay = _interopRequireDefault(require("../remove-picker-day-2"));
11
+ var _renamePickerDay = _interopRequireDefault(require("../rename-picker-day-2"));
12
+ var _renamePickersDay = _interopRequireDefault(require("../rename-pickers-day"));
13
+ var _renamePickerClasses = _interopRequireDefault(require("../rename-picker-classes"));
14
+ var _removeDisableMargin = _interopRequireDefault(require("../remove-disable-margin"));
15
+ var _removeEnableAccessibleFieldDomStructure = _interopRequireDefault(require("../remove-enable-accessible-field-dom-structure"));
16
+ // Order matters: removePickerDay2 must run before renamePickerDay2
17
+ // because it looks for `PickerDay2` identifiers in slot objects.
18
+ // If renamePickerDay2 ran first, those identifiers would already be
19
+ // renamed to `PickerDay` and removePickerDay2 would not find them.
20
+ const allModules = [_renameFieldRef.default, _removePickerDay.default, _renamePickerDay.default, _renamePickersDay.default, _renamePickerClasses.default, _removeDisableMargin.default, _removeEnableAccessibleFieldDomStructure.default];
9
21
  function transformer(file, api, options) {
10
- [_renameFieldRef.default].forEach(transform => {
22
+ allModules.forEach(transform => {
11
23
  file.source = transform(file, api, options);
12
24
  });
13
25
  return file.source;
14
- }
26
+ }
27
+ const testConfig = exports.testConfig = {
28
+ allModules
29
+ };
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = transformer;
8
+ exports.testConfig = void 0;
9
+ var _path = _interopRequireDefault(require("path"));
10
+ var _readFile = _interopRequireDefault(require("../../../util/readFile"));
11
+ // Components on which disableMargin was a direct prop
12
+ const dayComponentNames = ['PickerDay', 'PickersDay', 'DateRangePickerDay'];
13
+
14
+ /**
15
+ * Returns true if a disableMargin JSX attribute is considered enabled (i.e. `disableMargin` or
16
+ * `disableMargin={true}`). Returns false for `disableMargin={false}`.
17
+ */
18
+ function isDisableMarginEnabled(attr) {
19
+ if (!attr.value) {
20
+ // bare `disableMargin` with no value — equivalent to true
21
+ return true;
22
+ }
23
+ if (attr.value.type === 'JSXExpressionContainer' && attr.value.expression.type === 'BooleanLiteral') {
24
+ return attr.value.expression.value;
25
+ }
26
+ // Any other expression (variable, etc.) — conservatively treat as enabled
27
+ return true;
28
+ }
29
+ const cssVarKey = '--PickerDay-horizontalMargin';
30
+
31
+ /**
32
+ * Merges `'--PickerDay-horizontalMargin': 0` into an existing ObjectExpression used as an `sx` value.
33
+ * Only merges when the expression is a plain object literal.
34
+ * Returns true if the merge succeeded.
35
+ */
36
+ function mergeCssVarIntoSxObject(j, sxExpr) {
37
+ if (sxExpr.type !== 'ObjectExpression') {
38
+ return false;
39
+ }
40
+ // Avoid adding the CSS variable if it's already there
41
+ const alreadyHasVar = sxExpr.properties.some(p => p.type === 'ObjectProperty' && p.key?.value === cssVarKey);
42
+ if (!alreadyHasVar) {
43
+ sxExpr.properties.push(j.objectProperty(j.stringLiteral(cssVarKey), j.numericLiteral(0)));
44
+ }
45
+ return true;
46
+ }
47
+ function transformer(file, api, options) {
48
+ const j = api.jscodeshift;
49
+ const root = j(file.source);
50
+ const printOptions = options.printOptions || {
51
+ quote: 'single',
52
+ trailingComma: true
53
+ };
54
+
55
+ // ─── Case 1: disableMargin directly on a day component JSX element ───────────
56
+ root.find(j.JSXOpeningElement).filter(p => {
57
+ const name = p.node.name;
58
+ return name.type === 'JSXIdentifier' && dayComponentNames.includes(name.name);
59
+ }).forEach(openingElPath => {
60
+ const attrs = openingElPath.node.attributes;
61
+ const dmIndex = attrs.findIndex(a => a.type === 'JSXAttribute' && a.name?.name === 'disableMargin');
62
+ if (dmIndex === -1) {
63
+ return;
64
+ }
65
+ const dmAttr = attrs[dmIndex];
66
+ const enabled = isDisableMarginEnabled(dmAttr);
67
+ attrs.splice(dmIndex, 1);
68
+ if (enabled) {
69
+ const sxIndex = attrs.findIndex(a => a.type === 'JSXAttribute' && a.name?.name === 'sx');
70
+ if (sxIndex === -1) {
71
+ attrs.push(j.jsxAttribute(j.jsxIdentifier('sx'), j.jsxExpressionContainer(j.objectExpression([j.objectProperty(j.stringLiteral(cssVarKey), j.numericLiteral(0))]))));
72
+ } else {
73
+ const sxAttr = attrs[sxIndex];
74
+ if (sxAttr.value?.type === 'JSXExpressionContainer') {
75
+ mergeCssVarIntoSxObject(j, sxAttr.value.expression);
76
+ }
77
+ }
78
+ }
79
+ });
80
+
81
+ // ─── Case 2: disableMargin inside a slotProps.day object ─────────────────────
82
+ root.find(j.JSXAttribute, {
83
+ name: {
84
+ name: 'slotProps'
85
+ }
86
+ }).forEach(slotPropsAttrPath => {
87
+ const container = slotPropsAttrPath.node.value;
88
+ if (container?.type !== 'JSXExpressionContainer') {
89
+ return;
90
+ }
91
+ const slotPropsObj = container.expression;
92
+ if (slotPropsObj.type !== 'ObjectExpression') {
93
+ return;
94
+ }
95
+ slotPropsObj.properties.forEach(prop => {
96
+ if (prop.type !== 'ObjectProperty') {
97
+ return;
98
+ }
99
+ const keyName = prop.key?.name ?? prop.key?.value;
100
+ if (keyName !== 'day') {
101
+ return;
102
+ }
103
+ const dayObj = prop.value;
104
+ if (dayObj.type !== 'ObjectExpression') {
105
+ return;
106
+ }
107
+ const dmIndex = dayObj.properties.findIndex(p => p.type === 'ObjectProperty' && (p.key?.name === 'disableMargin' || p.key?.value === 'disableMargin'));
108
+ if (dmIndex === -1) {
109
+ return;
110
+ }
111
+ const dmProp = dayObj.properties[dmIndex];
112
+ const enabled = dmProp.value.type === 'BooleanLiteral' ? dmProp.value.value : true;
113
+ dayObj.properties.splice(dmIndex, 1);
114
+ if (enabled) {
115
+ const sxIndex = dayObj.properties.findIndex(p => p.type === 'ObjectProperty' && (p.key?.name === 'sx' || p.key?.value === 'sx'));
116
+ if (sxIndex === -1) {
117
+ dayObj.properties.push(j.objectProperty(j.identifier('sx'), j.objectExpression([j.objectProperty(j.stringLiteral(cssVarKey), j.numericLiteral(0))])));
118
+ } else {
119
+ mergeCssVarIntoSxObject(j, dayObj.properties[sxIndex].value);
120
+ }
121
+ }
122
+ });
123
+ });
124
+ return root.toSource(printOptions);
125
+ }
126
+ const testConfig = () => ({
127
+ name: 'remove-disable-margin',
128
+ specFiles: [{
129
+ name: "remove disableMargin prop and replace with sx={{ '--PickerDay-horizontalMargin': 0 }}",
130
+ actual: (0, _readFile.default)(_path.default.join(__dirname, 'actual.spec.tsx')),
131
+ expected: (0, _readFile.default)(_path.default.join(__dirname, 'expected.spec.tsx'))
132
+ }]
133
+ });
134
+ exports.testConfig = testConfig;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = transformer;
8
+ exports.testConfig = void 0;
9
+ var _path = _interopRequireDefault(require("path"));
10
+ var _removeProps = _interopRequireDefault(require("../../../util/removeProps"));
11
+ var _readFile = _interopRequireDefault(require("../../../util/readFile"));
12
+ const componentNames = ['DateField', 'DateTimeField', 'TimeField', 'DateRangeField', 'DateTimeRangeField', 'TimeRangeField', 'MultiInputDateRangeField', 'MultiInputDateTimeRangeField', 'MultiInputTimeRangeField', 'SingleInputDateRangeField', 'SingleInputDateTimeRangeField', 'SingleInputTimeRangeField', 'DatePicker', 'DesktopDatePicker', 'MobileDatePicker', 'StaticDatePicker', 'DateTimePicker', 'DesktopDateTimePicker', 'MobileDateTimePicker', 'StaticDateTimePicker', 'TimePicker', 'DesktopTimePicker', 'MobileTimePicker', 'StaticTimePicker', 'DateRangePicker', 'DesktopDateRangePicker', 'MobileDateRangePicker', 'StaticDateRangePicker', 'DateTimeRangePicker', 'DesktopDateTimeRangePicker', 'MobileDateTimeRangePicker', 'TimeRangePicker', 'DesktopTimeRangePicker', 'MobileTimeRangePicker'];
13
+ function transformer(file, api, options) {
14
+ const j = api.jscodeshift;
15
+ const root = j(file.source);
16
+ const printOptions = options.printOptions || {
17
+ quote: 'single',
18
+ trailingComma: true
19
+ };
20
+ (0, _removeProps.default)({
21
+ root,
22
+ j,
23
+ componentNames,
24
+ props: ['enableAccessibleFieldDOMStructure']
25
+ });
26
+
27
+ // Also remove enableAccessibleFieldDOMStructure from slotProps.field
28
+ componentNames.forEach(componentName => {
29
+ root.find(j.JSXElement, {
30
+ openingElement: {
31
+ name: {
32
+ name: componentName
33
+ }
34
+ }
35
+ }).forEach(elementPath => {
36
+ j(elementPath).find(j.JSXAttribute, {
37
+ name: {
38
+ name: 'slotProps'
39
+ }
40
+ }).forEach(slotPropsAttr => {
41
+ const value = slotPropsAttr.node.value;
42
+ if (value?.type !== 'JSXExpressionContainer' || value.expression.type !== 'ObjectExpression') {
43
+ return;
44
+ }
45
+ const fieldProp = value.expression.properties.find(p => p.key?.name === 'field' || p.key?.value === 'field');
46
+ if (!fieldProp || fieldProp.value.type !== 'ObjectExpression') {
47
+ return;
48
+ }
49
+ fieldProp.value.properties = fieldProp.value.properties.filter(p => p.key?.name !== 'enableAccessibleFieldDOMStructure' && p.key?.value !== 'enableAccessibleFieldDOMStructure');
50
+
51
+ // If field object is now empty, remove it from slotProps
52
+ if (fieldProp.value.properties.length === 0) {
53
+ value.expression.properties = value.expression.properties.filter(p => p !== fieldProp);
54
+ // If slotProps object is now empty, remove the whole attribute
55
+ if (value.expression.properties.length === 0) {
56
+ j(slotPropsAttr).remove();
57
+ }
58
+ }
59
+ });
60
+ });
61
+ });
62
+ return root.toSource(printOptions);
63
+ }
64
+ const testConfig = () => ({
65
+ name: 'remove-enable-accessible-field-dom-structure',
66
+ specFiles: [{
67
+ name: 'remove enableAccessibleFieldDOMStructure prop',
68
+ actual: (0, _readFile.default)(_path.default.join(__dirname, 'actual.spec.tsx')),
69
+ expected: (0, _readFile.default)(_path.default.join(__dirname, 'expected.spec.tsx'))
70
+ }]
71
+ });
72
+ exports.testConfig = testConfig;
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = transformer;
8
+ exports.testConfig = void 0;
9
+ var _path = _interopRequireDefault(require("path"));
10
+ var _readFile = _interopRequireDefault(require("../../../util/readFile"));
11
+ const pickerNames = ['DatePicker', 'DesktopDatePicker', 'MobileDatePicker', 'StaticDatePicker', 'DateTimePicker', 'DesktopDateTimePicker', 'MobileDateTimePicker', 'StaticDateTimePicker', 'TimePicker', 'DesktopTimePicker', 'MobileTimePicker', 'StaticTimePicker', 'DateRangePicker', 'DesktopDateRangePicker', 'MobileDateRangePicker', 'StaticDateRangePicker', 'DateTimeRangePicker', 'DesktopDateTimeRangePicker', 'MobileDateTimeRangePicker', 'TimeRangePicker', 'DesktopTimeRangePicker', 'MobileTimeRangePicker', 'DateCalendar', 'DayCalendar'];
12
+ function transformer(file, api, options) {
13
+ const j = api.jscodeshift;
14
+ const root = j(file.source);
15
+ const printOptions = options.printOptions || {
16
+ quote: 'single',
17
+ trailingComma: true
18
+ };
19
+ const dayComponents = ['PickerDay2', 'DateRangePickerDay2'];
20
+ root.find(j.ObjectExpression).forEach(objectExpressionPath => {
21
+ const properties = objectExpressionPath.node.properties;
22
+ const dayPropIndex = properties.findIndex(prop => {
23
+ const keyName = prop.key?.name || prop.key?.value;
24
+ if (keyName !== 'day') {
25
+ return false;
26
+ }
27
+ const val = prop.value;
28
+ return val.type === 'Identifier' && dayComponents.includes(val.name);
29
+ });
30
+ if (dayPropIndex !== -1) {
31
+ properties.splice(dayPropIndex, 1);
32
+ if (properties.length === 0) {
33
+ // Case 1: inline slots attribute — remove the entire slots prop
34
+ const attrCollection = j(objectExpressionPath).closest(j.JSXAttribute, {
35
+ name: {
36
+ name: 'slots'
37
+ }
38
+ });
39
+ if (attrCollection.length > 0) {
40
+ const openingElement = j(objectExpressionPath).closest(j.JSXOpeningElement);
41
+ if (openingElement.length > 0) {
42
+ const nameNode = openingElement.get().value.name;
43
+ const componentName = nameNode.type === 'JSXIdentifier' ? nameNode.name : null;
44
+ if (componentName && pickerNames.includes(componentName)) {
45
+ attrCollection.remove();
46
+ }
47
+ }
48
+ }
49
+
50
+ // Case 2: object is in a variable — remove slots={varName} on picker components,
51
+ // then remove the variable declaration if it becomes unreferenced
52
+ const varDeclarator = j(objectExpressionPath).closest(j.VariableDeclarator);
53
+ if (varDeclarator.length > 0) {
54
+ const varId = varDeclarator.get().value.id;
55
+ const varName = varId?.type === 'Identifier' ? varId.name : null;
56
+ if (varName) {
57
+ const slotsOnPickers = root.find(j.JSXAttribute, {
58
+ name: {
59
+ name: 'slots'
60
+ }
61
+ }).filter(attrPath => {
62
+ const val = attrPath.node.value;
63
+ return val?.type === 'JSXExpressionContainer' && val.expression.type === 'Identifier' && val.expression.name === varName;
64
+ }).filter(attrPath => {
65
+ const openingElement = j(attrPath).closest(j.JSXOpeningElement);
66
+ if (openingElement.length === 0) {
67
+ return false;
68
+ }
69
+ const nameNode = openingElement.get().value.name;
70
+ const componentName = nameNode.type === 'JSXIdentifier' ? nameNode.name : null;
71
+ return componentName !== null && pickerNames.includes(componentName);
72
+ });
73
+
74
+ // Check (before any mutation) whether varName has references outside
75
+ // of picker slots and the declaration binding itself.
76
+ const hasNonPickerRefs = root.find(j.Identifier, {
77
+ name: varName
78
+ }).filter(idPath => {
79
+ // find(j.Identifier) also matches JSXIdentifier (attribute names) — skip them
80
+ if (idPath.node.type !== 'Identifier') {
81
+ return false;
82
+ }
83
+ // Exclude the declaration binding (the `id` in `const varName = ...`)
84
+ if (idPath.name === 'id' && idPath.parent.value.type === 'VariableDeclarator') {
85
+ return false;
86
+ }
87
+ // Exclude references inside picker slots attributes (those are being removed)
88
+ const closestAttr = j(idPath).closest(j.JSXAttribute, {
89
+ name: {
90
+ name: 'slots'
91
+ }
92
+ });
93
+ if (closestAttr.length > 0) {
94
+ const openingElement = j(closestAttr.get()).closest(j.JSXOpeningElement);
95
+ if (openingElement.length > 0) {
96
+ const nameNode = openingElement.get().value.name;
97
+ const componentName = nameNode.type === 'JSXIdentifier' ? nameNode.name : null;
98
+ if (componentName && pickerNames.includes(componentName)) {
99
+ return false;
100
+ }
101
+ }
102
+ }
103
+ return true;
104
+ }).length > 0;
105
+ slotsOnPickers.remove();
106
+ if (!hasNonPickerRefs) {
107
+ varDeclarator.closest(j.VariableDeclaration).remove();
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ });
114
+
115
+ // Remove imports if no longer used
116
+ dayComponents.forEach(componentName => {
117
+ const usages = root.find(j.Identifier, {
118
+ name: componentName
119
+ }).filter(componentPath => {
120
+ const {
121
+ parent
122
+ } = componentPath;
123
+ if (parent.value.type === 'ImportSpecifier') {
124
+ return false;
125
+ }
126
+ return true;
127
+ });
128
+ if (usages.length === 0) {
129
+ root.find(j.ImportSpecifier, {
130
+ imported: {
131
+ name: componentName
132
+ }
133
+ }).filter(componentPath => {
134
+ const importDeclaration = componentPath.parentPath.parentPath.value;
135
+ return importDeclaration.source.value.startsWith('@mui/x-date-pickers') || importDeclaration.source.value.startsWith('@mui/x-date-pickers-pro');
136
+ }).forEach(componentPath => {
137
+ const importDeclaration = componentPath.parentPath.parentPath;
138
+ j(componentPath).remove();
139
+ if (importDeclaration.value.specifiers.length === 0) {
140
+ j(importDeclaration).remove();
141
+ }
142
+ });
143
+ }
144
+ });
145
+ return root.toSource(printOptions);
146
+ }
147
+ const testConfig = () => ({
148
+ name: 'remove-picker-day-2',
149
+ specFiles: [{
150
+ name: 'remove PickerDay2 and DateRangePickerDay2 from slots',
151
+ actual: (0, _readFile.default)(_path.default.join(__dirname, 'actual.spec.tsx')),
152
+ expected: (0, _readFile.default)(_path.default.join(__dirname, 'expected.spec.tsx'))
153
+ }]
154
+ });
155
+ exports.testConfig = testConfig;
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = transformer;
8
+ exports.testConfig = void 0;
9
+ var _path = _interopRequireDefault(require("path"));
10
+ var _readFile = _interopRequireDefault(require("../../../util/readFile"));
11
+ var _renameClasses = require("../../../util/renameClasses");
12
+ const classRenames = {
13
+ outsideCurrentMonth: 'dayOutsideMonth',
14
+ hiddenDayFiller: 'fillerCell',
15
+ hiddenDaySpacingFiller: 'fillerCell',
16
+ rangeIntervalDayHighlightStart: 'selectionStart',
17
+ rangeIntervalDayHighlightEnd: 'selectionEnd',
18
+ rangeIntervalDayPreviewStart: 'previewStart',
19
+ rangeIntervalDayPreviewEnd: 'previewEnd',
20
+ dayInsideRangeInterval: 'insideSelection',
21
+ rangeIntervalPreview: 'insidePreviewing',
22
+ rangeIntervalDayHighlight: 'selectionStart',
23
+ rangeIntervalDayPreview: 'previewStart'
24
+ };
25
+ function transformer(file, api, options) {
26
+ const j = api.jscodeshift;
27
+ const root = j(file.source);
28
+ const printOptions = options.printOptions || {
29
+ quote: 'single',
30
+ trailingComma: true
31
+ };
32
+ (0, _renameClasses.renameClasses)({
33
+ j,
34
+ root,
35
+ packageNames: ['@mui/x-date-pickers', '@mui/x-date-pickers-pro'],
36
+ classes: {
37
+ dateRangePickerDayClasses: {
38
+ newClassName: 'dateRangePickerDayClasses',
39
+ properties: classRenames
40
+ },
41
+ pickerDayClasses: {
42
+ newClassName: 'pickerDayClasses',
43
+ properties: classRenames
44
+ },
45
+ pickersDayClasses: {
46
+ newClassName: 'pickerDayClasses',
47
+ properties: classRenames
48
+ }
49
+ }
50
+ });
51
+
52
+ // Rename properties in styleOverrides
53
+ const componentsToHandle = ['MuiDateRangePickerDay', 'MuiPickerDay', 'MuiPickersDay'];
54
+ root.find(j.ObjectProperty).forEach(objPropPath => {
55
+ const keyName = objPropPath.node.key.type === 'Identifier' ? objPropPath.node.key.name : objPropPath.node.key.value;
56
+ if (componentsToHandle.includes(keyName) && objPropPath.node.value.type === 'ObjectExpression') {
57
+ j(objPropPath.node.value).find(j.ObjectProperty).filter(p => {
58
+ const k = p.node.key.type === 'Identifier' ? p.node.key.name : p.node.key.value;
59
+ return k === 'styleOverrides';
60
+ }).forEach(styleOverridesPath => {
61
+ if (styleOverridesPath.node.value.type === 'ObjectExpression') {
62
+ const seenProperties = new Map();
63
+ const indicesToRemove = new Set();
64
+ styleOverridesPath.node.value.properties.forEach((prop, index) => {
65
+ if (prop.type === 'ObjectProperty') {
66
+ const propKey = prop.key.type === 'Identifier' ? prop.key.name : prop.key.value;
67
+ const newKey = classRenames[propKey];
68
+ if (newKey) {
69
+ if (seenProperties.has(newKey)) {
70
+ const firstProp = seenProperties.get(newKey);
71
+ if (firstProp.value.type === 'ObjectExpression' && prop.value.type === 'ObjectExpression') {
72
+ firstProp.value.properties.push(...prop.value.properties);
73
+ }
74
+ indicesToRemove.add(index);
75
+ } else {
76
+ if (prop.key.type === 'Identifier') {
77
+ prop.key.name = newKey;
78
+ } else if (prop.key.type === 'StringLiteral') {
79
+ prop.key.value = newKey;
80
+ }
81
+ seenProperties.set(newKey, prop);
82
+ }
83
+ }
84
+ }
85
+ });
86
+ styleOverridesPath.node.value.properties = styleOverridesPath.node.value.properties.filter((_, index) => !indicesToRemove.has(index));
87
+ }
88
+ });
89
+ }
90
+ });
91
+
92
+ // Rename class names in strings and template literals.
93
+ // Only replace within known MUI component CSS class prefixes to avoid false positives.
94
+ const muiClassPrefixes = componentsToHandle.map(c => `${c}-`);
95
+ const replaceClasses = value => {
96
+ let newValue = value;
97
+ muiClassPrefixes.forEach(prefix => {
98
+ Object.keys(classRenames).forEach(oldClass => {
99
+ const newClass = classRenames[oldClass];
100
+ newValue = newValue.replace(new RegExp(`${prefix}${oldClass}\\b`, 'g'), `${prefix}${newClass}`);
101
+ });
102
+ });
103
+ return newValue;
104
+ };
105
+ root.find(j.StringLiteral).forEach(strPath => {
106
+ strPath.node.value = replaceClasses(strPath.node.value);
107
+ });
108
+ root.find(j.TemplateLiteral).forEach(templatePath => {
109
+ templatePath.node.quasis.forEach(quasi => {
110
+ quasi.value.raw = replaceClasses(quasi.value.raw);
111
+ if (quasi.value.cooked) {
112
+ quasi.value.cooked = replaceClasses(quasi.value.cooked);
113
+ }
114
+ });
115
+ });
116
+ return root.toSource(printOptions);
117
+ }
118
+ const testConfig = () => ({
119
+ name: 'rename-picker-classes',
120
+ specFiles: [{
121
+ name: 'rename PickerDay and DateRangePickerDay class keys',
122
+ actual: (0, _readFile.default)(_path.default.join(__dirname, 'actual.spec.tsx')),
123
+ expected: (0, _readFile.default)(_path.default.join(__dirname, 'expected.spec.tsx'))
124
+ }]
125
+ });
126
+ exports.testConfig = testConfig;
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = transformer;
8
+ exports.testConfig = void 0;
9
+ var _path = _interopRequireDefault(require("path"));
10
+ var _readFile = _interopRequireDefault(require("../../../util/readFile"));
11
+ function transformer(file, api, options) {
12
+ const j = api.jscodeshift;
13
+ const root = j(file.source);
14
+ const printOptions = options.printOptions || {
15
+ quote: 'single',
16
+ trailingComma: true
17
+ };
18
+ const renames = {
19
+ PickerDay2: 'PickerDay',
20
+ PickerDay2Props: 'PickerDayProps',
21
+ pickerDay2Classes: 'pickerDayClasses',
22
+ PickerDay2ClassKey: 'PickerDayClassKey',
23
+ PickerDay2Slots: 'PickerDaySlots',
24
+ PickerDay2SlotProps: 'PickerDaySlotProps',
25
+ PickerDay2OwnerState: 'PickerDayOwnerState',
26
+ DateRangePickerDay2: 'DateRangePickerDay',
27
+ DateRangePickerDay2Props: 'DateRangePickerDayProps',
28
+ dateRangePickerDay2Classes: 'dateRangePickerDayClasses',
29
+ DateRangePickerDay2ClassKey: 'DateRangePickerDayClassKey',
30
+ DateRangePickerDay2Slots: 'DateRangePickerDaySlots',
31
+ DateRangePickerDay2SlotProps: 'DateRangePickerDaySlotProps',
32
+ DateRangePickerDay2OwnerState: 'DateRangePickerDayOwnerState'
33
+ };
34
+ const renameKeys = Object.keys(renames);
35
+
36
+ // Rename imports and usages
37
+ renameKeys.forEach(oldName => {
38
+ const newName = renames[oldName];
39
+ root.find(j.Identifier, {
40
+ name: oldName
41
+ }).forEach(keyPath => {
42
+ // Avoid renaming property keys in objects unless they are shorthand or identifiers in other contexts
43
+ if (keyPath.parent.value.type === 'Property' && keyPath.parent.value.key === keyPath.node && !keyPath.parent.value.shorthand) {
44
+ return;
45
+ }
46
+ // Avoid renaming member expressions like something.PickerDay2
47
+ if (keyPath.parent.value.type === 'MemberExpression' && keyPath.parent.value.property === keyPath.node && !keyPath.parent.value.computed) {
48
+ return;
49
+ }
50
+ j(keyPath).replaceWith(j.identifier(newName));
51
+ });
52
+ });
53
+
54
+ // Rename theme components in createTheme / theme augmentation
55
+ root.find(j.Identifier, {
56
+ name: 'MuiPickerDay2'
57
+ }).forEach(keyPath => {
58
+ j(keyPath).replaceWith(j.identifier('MuiPickerDay'));
59
+ });
60
+ root.find(j.Identifier, {
61
+ name: 'MuiDateRangePickerDay2'
62
+ }).forEach(keyPath => {
63
+ j(keyPath).replaceWith(j.identifier('MuiDateRangePickerDay'));
64
+ });
65
+
66
+ // Also handle string literals and template literals
67
+ const replaceClass = value => value.replace(/MuiPickerDay2\b/g, 'MuiPickerDay').replace(/MuiDateRangePickerDay2\b/g, 'MuiDateRangePickerDay');
68
+ root.find(j.StringLiteral).forEach(keyPath => {
69
+ if (keyPath.value.value.includes('MuiPickerDay2') || keyPath.value.value.includes('MuiDateRangePickerDay2')) {
70
+ j(keyPath).replaceWith(j.stringLiteral(replaceClass(keyPath.value.value)));
71
+ }
72
+ });
73
+ root.find(j.TemplateLiteral).forEach(keyPath => {
74
+ keyPath.value.quasis.forEach(quasi => {
75
+ if (quasi.value.raw.includes('MuiPickerDay2') || quasi.value.raw.includes('MuiDateRangePickerDay2')) {
76
+ quasi.value.raw = replaceClass(quasi.value.raw);
77
+ }
78
+ if (quasi.value.cooked && (quasi.value.cooked.includes('MuiPickerDay2') || quasi.value.cooked.includes('MuiDateRangePickerDay2'))) {
79
+ quasi.value.cooked = replaceClass(quasi.value.cooked);
80
+ }
81
+ });
82
+ });
83
+
84
+ // Update import sources
85
+ root.find(j.ImportDeclaration).forEach(importPath => {
86
+ if (typeof importPath.value.source.value === 'string') {
87
+ if (importPath.value.source.value.includes('/PickerDay2')) {
88
+ importPath.value.source.value = importPath.value.source.value.replace('/PickerDay2', '/PickerDay');
89
+ }
90
+ if (importPath.value.source.value.includes('/DateRangePickerDay2')) {
91
+ importPath.value.source.value = importPath.value.source.value.replace('/DateRangePickerDay2', '/DateRangePickerDay');
92
+ }
93
+ }
94
+ });
95
+ return root.toSource(printOptions);
96
+ }
97
+ const testConfig = () => ({
98
+ name: 'rename-picker-day-2',
99
+ specFiles: [{
100
+ name: 'rename PickerDay2 and DateRangePickerDay2 to PickerDay and DateRangePickerDay',
101
+ actual: (0, _readFile.default)(_path.default.join(__dirname, 'actual.spec.tsx')),
102
+ expected: (0, _readFile.default)(_path.default.join(__dirname, 'expected.spec.tsx'))
103
+ }]
104
+ });
105
+ exports.testConfig = testConfig;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = transformer;
8
+ exports.testConfig = void 0;
9
+ var _path = _interopRequireDefault(require("path"));
10
+ var _readFile = _interopRequireDefault(require("../../../util/readFile"));
11
+ function transformer(file, api, options) {
12
+ const j = api.jscodeshift;
13
+ const root = j(file.source);
14
+ const printOptions = options.printOptions || {
15
+ quote: 'single',
16
+ trailingComma: true
17
+ };
18
+ const renames = {
19
+ PickersDay: 'PickerDay',
20
+ PickersDayProps: 'PickerDayProps',
21
+ pickersDayClasses: 'pickerDayClasses',
22
+ PickersDayClassKey: 'PickerDayClassKey',
23
+ PickersDaySlots: 'PickerDaySlots',
24
+ PickersDaySlotProps: 'PickerDaySlotProps',
25
+ PickersDayOwnerState: 'PickerDayOwnerState'
26
+ };
27
+ const renameKeys = Object.keys(renames);
28
+
29
+ // Rename imports and usages
30
+ renameKeys.forEach(oldName => {
31
+ const newName = renames[oldName];
32
+ root.find(j.Identifier, {
33
+ name: oldName
34
+ }).forEach(keyPath => {
35
+ // Avoid renaming property keys in objects unless they are shorthand or identifiers in other contexts
36
+ if (keyPath.parent.value.type === 'Property' && keyPath.parent.value.key === keyPath.node && !keyPath.parent.value.shorthand) {
37
+ return;
38
+ }
39
+ // Avoid renaming member expressions like something.PickersDay
40
+ if (keyPath.parent.value.type === 'MemberExpression' && keyPath.parent.value.property === keyPath.node && !keyPath.parent.value.computed) {
41
+ return;
42
+ }
43
+ j(keyPath).replaceWith(j.identifier(newName));
44
+ });
45
+ });
46
+
47
+ // Rename theme components in createTheme / theme augmentation
48
+ root.find(j.Identifier, {
49
+ name: 'MuiPickersDay'
50
+ }).forEach(keyPath => {
51
+ j(keyPath).replaceWith(j.identifier('MuiPickerDay'));
52
+ });
53
+
54
+ // Also handle string literals and template literals for MuiPickersDay if any (e.g. in theme overrides or sx)
55
+ const replaceClass = value => value.replace(/MuiPickersDay\b/g, 'MuiPickerDay');
56
+ root.find(j.StringLiteral).forEach(keyPath => {
57
+ if (keyPath.value.value.includes('MuiPickersDay')) {
58
+ j(keyPath).replaceWith(j.stringLiteral(replaceClass(keyPath.value.value)));
59
+ }
60
+ });
61
+ root.find(j.TemplateLiteral).forEach(keyPath => {
62
+ keyPath.value.quasis.forEach(quasi => {
63
+ if (quasi.value.raw.includes('MuiPickersDay')) {
64
+ quasi.value.raw = replaceClass(quasi.value.raw);
65
+ }
66
+ if (quasi.value.cooked && quasi.value.cooked.includes('MuiPickersDay')) {
67
+ quasi.value.cooked = replaceClass(quasi.value.cooked);
68
+ }
69
+ });
70
+ });
71
+
72
+ // Update import sources if they point to PickersDay (though usually they point to @mui/x-date-pickers)
73
+ root.find(j.ImportDeclaration).forEach(importPath => {
74
+ if (typeof importPath.value.source.value === 'string') {
75
+ if (importPath.value.source.value.includes('/PickersDay')) {
76
+ importPath.value.source.value = importPath.value.source.value.replace('/PickersDay', '/PickerDay');
77
+ }
78
+ }
79
+ });
80
+ return root.toSource(printOptions);
81
+ }
82
+ const testConfig = () => ({
83
+ name: 'rename-pickers-day',
84
+ specFiles: [{
85
+ name: 'rename PickersDay to PickerDay and related types',
86
+ actual: (0, _readFile.default)(_path.default.join(__dirname, 'actual.spec.tsx')),
87
+ expected: (0, _readFile.default)(_path.default.join(__dirname, 'expected.spec.tsx'))
88
+ }]
89
+ });
90
+ exports.testConfig = testConfig;