-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
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][TableSortLabel] Introduce slots and slotProps #42157
Changes from 7 commits
3c13ef8
b722f71
5f23e3f
3f01a0e
6c3ee19
e256e02
7cb57cb
876b71f
02e2722
fe8f8f2
d9dfdfd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from './table-sort-label-props'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import replaceComponentsWithSlots from '../utils/replaceComponentsWithSlots'; | ||
import movePropIntoSlots from '../utils/movePropIntoSlots'; | ||
|
||
/** | ||
* @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: 'TableSortLabel' }); | ||
|
||
movePropIntoSlots(j, { | ||
root, | ||
componentName: 'TableSortLabel', | ||
propName: 'IconComponent', | ||
slotName: 'icon', | ||
}); | ||
|
||
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 './table-sort-label-props'; | ||
import readFile from '../../util/readFile'; | ||
|
||
function read(fileName) { | ||
return readFile(path.join(__dirname, fileName)); | ||
} | ||
|
||
describe('@mui/codemod', () => { | ||
describe('deprecations', () => { | ||
describe('table-sort-label-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] table-sort-label-props', () => { | ||
it('transforms props as needed', () => { | ||
const actual = transform( | ||
{ source: read('./test-cases/theme.actual.js') }, | ||
{ jscodeshift }, | ||
{ printOptions: { trailingComma: true } }, | ||
); | ||
|
||
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,3 @@ | ||
import TableSortLabel from '@mui/material/TableSortLabel'; | ||
|
||
<TableSortLabel IconComponent={IconComponent} />; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import TableSortLabel from '@mui/material/TableSortLabel'; | ||
|
||
<TableSortLabel slots={{ | ||
icon: IconComponent | ||
}} />; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
fn({ | ||
MuiTableSortLabel: { | ||
defaultProps: { | ||
IconComponent: IconComponent, | ||
}, | ||
}, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
fn({ | ||
MuiTableSortLabel: { | ||
defaultProps: { | ||
slots: { | ||
icon: IconComponent, | ||
}, | ||
}, | ||
}, | ||
}); |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -9,6 +9,7 @@ import styled from '../styles/styled'; | |||
import useThemeProps from '../styles/useThemeProps'; | ||||
import capitalize from '../utils/capitalize'; | ||||
import tableSortLabelClasses, { getTableSortLabelUtilityClass } from './tableSortLabelClasses'; | ||||
import useSlot from '../utils/useSlot'; | ||||
|
||||
const useUtilityClasses = (ownerState) => { | ||||
const { classes, direction, active } = ownerState; | ||||
|
@@ -102,6 +103,8 @@ const TableSortLabel = React.forwardRef(function TableSortLabel(inProps, ref) { | |||
direction = 'asc', | ||||
hideSortIcon = false, | ||||
IconComponent = ArrowDownwardIcon, | ||||
slots = {}, | ||||
slotProps = {}, | ||||
...other | ||||
} = props; | ||||
|
||||
|
@@ -115,6 +118,17 @@ const TableSortLabel = React.forwardRef(function TableSortLabel(inProps, ref) { | |||
|
||||
const classes = useUtilityClasses(ownerState); | ||||
|
||||
const externalForwardedProps = { | ||||
slots, | ||||
slotProps, | ||||
}; | ||||
|
||||
const [IconSlot, iconProps] = useSlot('icon', { | ||||
elementType: IconComponent, | ||||
externalForwardedProps, | ||||
ownerState, | ||||
}); | ||||
|
||||
return ( | ||||
<TableSortLabelRoot | ||||
className={clsx(classes.root, className)} | ||||
|
@@ -126,11 +140,7 @@ const TableSortLabel = React.forwardRef(function TableSortLabel(inProps, ref) { | |||
> | ||||
{children} | ||||
{hideSortIcon && !active ? null : ( | ||||
<TableSortLabelIcon | ||||
as={IconComponent} | ||||
className={clsx(classes.icon)} | ||||
ownerState={ownerState} | ||||
/> | ||||
<TableSortLabelIcon as={IconSlot} className={clsx(classes.icon)} {...iconProps} /> | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be: const externalForwardedProps = {
slots: {
icon: IconComponent,
...slots
},
slotProps,
};
const [IconSlot, iconProps] = useSlot('icon', {
elementType: TableSortLabelIcon,
externalForwardedProps,
ownerState,
className: classes.icon
});
// ...
<IconSlot {...iconProps} /> There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just realized we did the same in https://github.com/mui/material-ui/pull/41875/files#diff-d626958b0fab135d0026b2cf86b08f733dae8abb98fc406df247b3846dcf8589R651 We will need to fix that 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are you sure? By going with above approach
slots[name] (here: IconComponent) preceeds over initialElementType ( here: TableSortLabelIcon) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I see what's happening. There are some <DefaultComponent
as={ComponentProp}
/> But others are used as const { ComponentProp: DefaultComponent } = props
// ...
<ComponentProp /> Which is different. If I'm not mistaken, the convention for the slot pattern is to work as the latter: When you provide a slot, it replaces the default completely. Is this correct @siriwatknp? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Other components with the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, but let's wait for confirmation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Agree with the first two. I don't think the last is needed. Currently, we don't document There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
But what should we say the replacement for
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey @DiegoAndai @siriwatknp any discussion happened on this PR front ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry for the delay @sai6855. I think this is a special case (the same for other |
||||
)} | ||||
</TableSortLabelRoot> | ||||
); | ||||
|
@@ -171,8 +181,23 @@ TableSortLabel.propTypes /* remove-proptypes */ = { | |||
/** | ||||
* Sort icon to use. | ||||
* @default ArrowDownwardIcon | ||||
* @deprecated Use `slots.icon` instead. This prop will be removed in v7. See [Migrating from deprecated APIs](/material-ui/migration/migrating-from-deprecated-apis/) for more details. | ||||
*/ | ||||
IconComponent: PropTypes.elementType, | ||||
/** | ||||
* The props used for each slot inside. | ||||
* @default {} | ||||
*/ | ||||
slotProps: PropTypes.shape({ | ||||
icon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), | ||||
}), | ||||
/** | ||||
* The components used for each slot inside. | ||||
* @default {} | ||||
*/ | ||||
slots: PropTypes.shape({ | ||||
icon: PropTypes.elementType, | ||||
}), | ||||
/** | ||||
* The system prop that allows defining system overrides as well as additional CSS styles. | ||||
*/ | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this required?