diff --git a/docs/data/base/components/badge/badge.md b/docs/data/base/components/badge/badge.md index 89093081f9a8c9..86d50f69308bab 100644 --- a/docs/data/base/components/badge/badge.md +++ b/docs/data/base/components/badge/badge.md @@ -71,27 +71,23 @@ Use the `component` prop to override the root slot with a custom element: ``` -Use the `components` prop to override any interior slots in addition to the root: +Use the `slots` prop to override any interior slots in addition to the root: ```jsx - + ``` :::warning -If the root element is customized with both the `component` and `components` props, then `component` will take precedence. +If the root element is customized with both the `component` and `slots` props, then `component` will take precedence. ::: -Use the `componentsProps` prop to pass custom props to internal slots. +Use the `slotProps` prop to pass custom props to internal slots. The following code snippet applies a CSS class called `my-badge` to the badge slot: ```jsx - + ``` -:::warning -Note that `componentsProps` slot names are written in lowercase (`root`) while `components` slot names are capitalized (`Root`). -::: - ## Hook ```jsx diff --git a/docs/data/base/components/button/button.md b/docs/data/base/components/button/button.md index 09a71ca69b37c9..6ed05fa45f2e2c 100644 --- a/docs/data/base/components/button/button.md +++ b/docs/data/base/components/button/button.md @@ -66,27 +66,23 @@ Use the `component` prop to override the root slot with a custom element: If you provide a non-interactive element such as a ``, the `ButtonUnstyled` component will automatically add the necessary accessibility attributes. -Use the `components` prop to override any interior slots in addition to the root: +Use the `slots` prop to override any interior slots in addition to the root: ```jsx - + ``` :::warning -If the root element is customized with both the `component` and `components` props, then `component` will take precedence. +If the root element is customized with both the `component` and `slots` props, then `component` will take precedence. ::: -Use the `componentsProps` prop to pass custom props to internal slots. +Use the `slotProps` prop to pass custom props to internal slots. The following code snippet applies a CSS class called `my-button` to the root slot: ```jsx - + ``` -:::warning -Note that `componentsProps` slot names are written in lowercase (`root`) while `components` slot names are capitalized (`Root`). -::: - Compare the attributes on the `` in this demo with the `ButtonUnstyled` from the previous demo: {{"demo": "UnstyledButtonsSpan.js"}} diff --git a/docs/data/base/components/input/InputAdornments.js b/docs/data/base/components/input/InputAdornments.js index 4975c515b5b5b0..25f30675047bc8 100644 --- a/docs/data/base/components/input/InputAdornments.js +++ b/docs/data/base/components/input/InputAdornments.js @@ -89,13 +89,13 @@ const InputAdornment = styled('div')` `; const CustomInput = React.forwardRef(function CustomInput(props, ref) { - const { components, ...other } = props; + const { slots, ...other } = props; return ( , ) { - const { components, ...other } = props; + const { slots, ...other } = props; return ( diff --git a/docs/data/base/components/input/InputMultiline.tsx b/docs/data/base/components/input/InputMultiline.tsx index 1e389ce2ae1a13..e377f1de40adc7 100644 --- a/docs/data/base/components/input/InputMultiline.tsx +++ b/docs/data/base/components/input/InputMultiline.tsx @@ -82,7 +82,7 @@ const CustomInput = React.forwardRef(function CustomInput( ) { return ( diff --git a/docs/data/base/components/input/InputMultilineAutosize.js b/docs/data/base/components/input/InputMultilineAutosize.js index 902d8a124e6bf5..c202de92f4a90e 100644 --- a/docs/data/base/components/input/InputMultilineAutosize.js +++ b/docs/data/base/components/input/InputMultilineAutosize.js @@ -77,7 +77,7 @@ const StyledTextareaElement = styled(TextareaAutosize)( const CustomInput = React.forwardRef(function CustomInput(props, ref) { return ( diff --git a/docs/data/base/components/input/InputMultilineAutosize.tsx b/docs/data/base/components/input/InputMultilineAutosize.tsx index 9a94b64750707e..7b4e67b8ec6375 100644 --- a/docs/data/base/components/input/InputMultilineAutosize.tsx +++ b/docs/data/base/components/input/InputMultilineAutosize.tsx @@ -80,7 +80,7 @@ const CustomInput = React.forwardRef(function CustomInput( ) { return ( diff --git a/docs/data/base/components/input/UnstyledInputBasic.js b/docs/data/base/components/input/UnstyledInputBasic.js index a5724a558b70d4..be86fab1ec7dfd 100644 --- a/docs/data/base/components/input/UnstyledInputBasic.js +++ b/docs/data/base/components/input/UnstyledInputBasic.js @@ -50,7 +50,7 @@ const StyledInputElement = styled('input')( const CustomInput = React.forwardRef(function CustomInput(props, ref) { return ( - + ); }); diff --git a/docs/data/base/components/input/UnstyledInputBasic.tsx b/docs/data/base/components/input/UnstyledInputBasic.tsx index 810a017b6f3554..ec7e71c96c72c7 100644 --- a/docs/data/base/components/input/UnstyledInputBasic.tsx +++ b/docs/data/base/components/input/UnstyledInputBasic.tsx @@ -53,7 +53,7 @@ const CustomInput = React.forwardRef(function CustomInput( ref: React.ForwardedRef, ) { return ( - + ); }); diff --git a/docs/data/base/components/input/UnstyledInputIntroduction.js b/docs/data/base/components/input/UnstyledInputIntroduction.js index e7fdf20a3fe5af..08c9c848375c0e 100644 --- a/docs/data/base/components/input/UnstyledInputIntroduction.js +++ b/docs/data/base/components/input/UnstyledInputIntroduction.js @@ -50,7 +50,7 @@ const StyledInputElement = styled('input')( const CustomInput = React.forwardRef(function CustomInput(props, ref) { return ( - + ); }); diff --git a/docs/data/base/components/input/UnstyledInputIntroduction.tsx b/docs/data/base/components/input/UnstyledInputIntroduction.tsx index e55d3e22964fb9..7f5703901e9a3b 100644 --- a/docs/data/base/components/input/UnstyledInputIntroduction.tsx +++ b/docs/data/base/components/input/UnstyledInputIntroduction.tsx @@ -53,7 +53,7 @@ const CustomInput = React.forwardRef(function CustomInput( ref: React.ForwardedRef, ) { return ( - + ); }); diff --git a/docs/data/base/components/input/input.md b/docs/data/base/components/input/input.md index 98ae3edd979b2d..204775fe61c738 100644 --- a/docs/data/base/components/input/input.md +++ b/docs/data/base/components/input/input.md @@ -69,27 +69,23 @@ Use the `component` prop to override the root slot with a custom element: ``` -Use the `components` prop to override any interior slots in addition to the root: +Use the `slots` prop to override any interior slots in addition to the root: ```jsx - + ``` :::warning -If the root element is customized with both the `component` and `components` props, then `component` will take precedence. +If the root element is customized with both the `component` and `slots` props, then `component` will take precedence. ::: -Use the `componentsProps` prop to pass custom props to internal slots. +Use the `slotProps` prop to pass custom props to internal slots. The following code snippet applies a CSS class called `my-input` to the input slot: ```jsx - + ``` -:::warning -Note that `componentsProps` slot names are written in lowercase (`root`) while `components` slot names are capitalized (`Root`). -::: - ## Hook ```js diff --git a/docs/data/base/components/menu/MenuSimple.js b/docs/data/base/components/menu/MenuSimple.js index f416b0d0e44cbe..77db806273f1f5 100644 --- a/docs/data/base/components/menu/MenuSimple.js +++ b/docs/data/base/components/menu/MenuSimple.js @@ -179,8 +179,8 @@ export default function UnstyledMenuSimple() { open={isOpen} onClose={close} anchorEl={anchorEl} - components={{ Root: Popper, Listbox: StyledListbox }} - componentsProps={{ listbox: { id: 'simple-menu' } }} + slots={{ root: Popper, listbox: StyledListbox }} + slotProps={{ listbox: { id: 'simple-menu' } }} > Profile diff --git a/docs/data/base/components/menu/MenuSimple.tsx b/docs/data/base/components/menu/MenuSimple.tsx index f1243e2f4f63f3..45c808d067637c 100644 --- a/docs/data/base/components/menu/MenuSimple.tsx +++ b/docs/data/base/components/menu/MenuSimple.tsx @@ -179,8 +179,8 @@ export default function UnstyledMenuSimple() { open={isOpen} onClose={close} anchorEl={anchorEl} - components={{ Root: Popper, Listbox: StyledListbox }} - componentsProps={{ listbox: { id: 'simple-menu' } }} + slots={{ root: Popper, listbox: StyledListbox }} + slotProps={{ listbox: { id: 'simple-menu' } }} > Profile diff --git a/docs/data/base/components/menu/UnstyledMenuIntroduction.js b/docs/data/base/components/menu/UnstyledMenuIntroduction.js index 71b3e7f7ab0f76..50c82ae9f27cd6 100644 --- a/docs/data/base/components/menu/UnstyledMenuIntroduction.js +++ b/docs/data/base/components/menu/UnstyledMenuIntroduction.js @@ -162,8 +162,8 @@ export default function UnstyledMenuIntroduction() { open={isOpen} onClose={close} anchorEl={anchorEl} - components={{ Root: Popper, Listbox: StyledListbox }} - componentsProps={{ listbox: { id: 'simple-menu' } }} + slots={{ root: Popper, listbox: StyledListbox }} + slotProps={{ listbox: { id: 'simple-menu' } }} > Profile diff --git a/docs/data/base/components/menu/UnstyledMenuIntroduction.tsx b/docs/data/base/components/menu/UnstyledMenuIntroduction.tsx index 291915dea47bcc..1d5fe1b89b5b4a 100644 --- a/docs/data/base/components/menu/UnstyledMenuIntroduction.tsx +++ b/docs/data/base/components/menu/UnstyledMenuIntroduction.tsx @@ -162,8 +162,8 @@ export default function UnstyledMenuIntroduction() { open={isOpen} onClose={close} anchorEl={anchorEl} - components={{ Root: Popper, Listbox: StyledListbox }} - componentsProps={{ listbox: { id: 'simple-menu' } }} + slots={{ root: Popper, listbox: StyledListbox }} + slotProps={{ listbox: { id: 'simple-menu' } }} > Profile diff --git a/docs/data/base/components/menu/WrappedMenuItems.js b/docs/data/base/components/menu/WrappedMenuItems.js index 575bfb83066a1e..586c67225d77cb 100644 --- a/docs/data/base/components/menu/WrappedMenuItems.js +++ b/docs/data/base/components/menu/WrappedMenuItems.js @@ -212,8 +212,8 @@ export default function WrappedMenuItems() { open={isOpen} onClose={close} anchorEl={anchorEl} - components={{ Root: Popper, Listbox: StyledListbox }} - componentsProps={{ listbox: { id: 'simple-menu' } }} + slots={{ root: Popper, listbox: StyledListbox }} + slotProps={{ listbox: { id: 'simple-menu' } }} > diff --git a/docs/data/base/components/menu/WrappedMenuItems.tsx b/docs/data/base/components/menu/WrappedMenuItems.tsx index cd0b0928b78cd3..230519f472b65b 100644 --- a/docs/data/base/components/menu/WrappedMenuItems.tsx +++ b/docs/data/base/components/menu/WrappedMenuItems.tsx @@ -211,8 +211,8 @@ export default function WrappedMenuItems() { open={isOpen} onClose={close} anchorEl={anchorEl} - components={{ Root: Popper, Listbox: StyledListbox }} - componentsProps={{ listbox: { id: 'simple-menu' } }} + slots={{ root: Popper, listbox: StyledListbox }} + slotProps={{ listbox: { id: 'simple-menu' } }} > diff --git a/docs/data/base/components/menu/menu.md b/docs/data/base/components/menu/menu.md index 70845e1008fd7f..0436d4801d9284 100644 --- a/docs/data/base/components/menu/menu.md +++ b/docs/data/base/components/menu/menu.md @@ -78,27 +78,23 @@ Use the `component` prop to override the root slot with a custom element: ``` -Use the `components` prop to override any interior slots in addition to the root: +Use the `slots` prop to override any interior slots in addition to the root: ```jsx - + ``` :::warning -If the root element is customized with both the `component` and `components` props, then `component` will take precedence. +If the root element is customized with both the `component` and `slots` props, then `component` will take precedence. ::: -Use the `componentsProps` prop to pass custom props to internal slots. +Use the `slotProps` prop to pass custom props to internal slots. The following code snippet applies a CSS class called `my-listbox` to the listbox slot: ```jsx - + ``` -:::warning -Note that `componentsProps` slot names are written in lowercase (`root`) while `components` slot names are capitalized (`Root`). -::: - ### CSS classes `MenuUnstyled` can set the following class: diff --git a/docs/data/base/components/modal/KeepMountedModal.js b/docs/data/base/components/modal/KeepMountedModal.js index 366c2a66ed78b5..546d1e24fc3de8 100644 --- a/docs/data/base/components/modal/KeepMountedModal.js +++ b/docs/data/base/components/modal/KeepMountedModal.js @@ -68,7 +68,7 @@ export default function ModalUnstyledDemo() { aria-describedby="keep-mounted-modal-description" open={open} onClose={handleClose} - components={{ Backdrop }} + slots={{ backdrop: Backdrop }} keepMounted > diff --git a/docs/data/base/components/modal/KeepMountedModal.tsx b/docs/data/base/components/modal/KeepMountedModal.tsx index d05bea985dd2e2..95bea81f5546f3 100644 --- a/docs/data/base/components/modal/KeepMountedModal.tsx +++ b/docs/data/base/components/modal/KeepMountedModal.tsx @@ -65,7 +65,7 @@ export default function ModalUnstyledDemo() { aria-describedby="keep-mounted-modal-description" open={open} onClose={handleClose} - components={{ Backdrop }} + slots={{ backdrop: Backdrop }} keepMounted > diff --git a/docs/data/base/components/modal/KeepMountedModal.tsx.preview b/docs/data/base/components/modal/KeepMountedModal.tsx.preview index ee11c0bb16b8cc..5c75bfb3f238dc 100644 --- a/docs/data/base/components/modal/KeepMountedModal.tsx.preview +++ b/docs/data/base/components/modal/KeepMountedModal.tsx.preview @@ -6,7 +6,7 @@ aria-describedby="keep-mounted-modal-description" open={open} onClose={handleClose} - components={{ Backdrop }} + slots={{ backdrop: Backdrop }} keepMounted > diff --git a/docs/data/base/components/modal/ModalUnstyled.js b/docs/data/base/components/modal/ModalUnstyled.js index 2040f54e71af25..196507ec5245b3 100644 --- a/docs/data/base/components/modal/ModalUnstyled.js +++ b/docs/data/base/components/modal/ModalUnstyled.js @@ -65,7 +65,7 @@ export default function ModalUnstyledDemo() { aria-describedby="unstyled-modal-description" open={open} onClose={handleClose} - components={{ Backdrop }} + slots={{ backdrop: Backdrop }} >

Text in a modal

diff --git a/docs/data/base/components/modal/ModalUnstyled.tsx b/docs/data/base/components/modal/ModalUnstyled.tsx index d95446f30a7a70..8bb0cd53ec23b1 100644 --- a/docs/data/base/components/modal/ModalUnstyled.tsx +++ b/docs/data/base/components/modal/ModalUnstyled.tsx @@ -62,7 +62,7 @@ export default function ModalUnstyledDemo() { aria-describedby="unstyled-modal-description" open={open} onClose={handleClose} - components={{ Backdrop }} + slots={{ backdrop: Backdrop }} >

Text in a modal

diff --git a/docs/data/base/components/modal/ModalUnstyled.tsx.preview b/docs/data/base/components/modal/ModalUnstyled.tsx.preview index 399fb59cd55e22..98dcf846bda928 100644 --- a/docs/data/base/components/modal/ModalUnstyled.tsx.preview +++ b/docs/data/base/components/modal/ModalUnstyled.tsx.preview @@ -6,7 +6,7 @@ aria-describedby="unstyled-modal-description" open={open} onClose={handleClose} - components={{ Backdrop }} + slots={{ backdrop: Backdrop }} >

Text in a modal

diff --git a/docs/data/base/components/modal/NestedModal.js b/docs/data/base/components/modal/NestedModal.js index 57be9d5b800eec..2884229180f748 100644 --- a/docs/data/base/components/modal/NestedModal.js +++ b/docs/data/base/components/modal/NestedModal.js @@ -103,7 +103,7 @@ export default function NestedModal() { onClose={handleClose} aria-labelledby="parent-modal-title" aria-describedby="parent-modal-description" - components={{ Backdrop }} + slots={{ backdrop: Backdrop }} >

Text in a modal

diff --git a/docs/data/base/components/modal/NestedModal.tsx b/docs/data/base/components/modal/NestedModal.tsx index 6033402d47c44c..dd3d4b6509e396 100644 --- a/docs/data/base/components/modal/NestedModal.tsx +++ b/docs/data/base/components/modal/NestedModal.tsx @@ -100,7 +100,7 @@ export default function NestedModal() { onClose={handleClose} aria-labelledby="parent-modal-title" aria-describedby="parent-modal-description" - components={{ Backdrop }} + slots={{ backdrop: Backdrop }} >

Text in a modal

diff --git a/docs/data/base/components/modal/NestedModal.tsx.preview b/docs/data/base/components/modal/NestedModal.tsx.preview index 628e6f78a6ae47..6e3e8cf5c40251 100644 --- a/docs/data/base/components/modal/NestedModal.tsx.preview +++ b/docs/data/base/components/modal/NestedModal.tsx.preview @@ -4,7 +4,7 @@ onClose={handleClose} aria-labelledby="parent-modal-title" aria-describedby="parent-modal-description" - components={{ Backdrop }} + slots={{ backdrop: Backdrop }} >

Text in a modal

diff --git a/docs/data/base/components/modal/SpringModal.js b/docs/data/base/components/modal/SpringModal.js index 1ba6a4849f2a8e..17ebe3b3833395 100644 --- a/docs/data/base/components/modal/SpringModal.js +++ b/docs/data/base/components/modal/SpringModal.js @@ -103,7 +103,7 @@ export default function SpringModal() { open={open} onClose={handleClose} closeAfterTransition - components={{ Backdrop }} + slots={{ backdrop: Backdrop }} > diff --git a/docs/data/base/components/modal/SpringModal.tsx b/docs/data/base/components/modal/SpringModal.tsx index 9179173f365980..82524c7d45e168 100644 --- a/docs/data/base/components/modal/SpringModal.tsx +++ b/docs/data/base/components/modal/SpringModal.tsx @@ -100,7 +100,7 @@ export default function SpringModal() { open={open} onClose={handleClose} closeAfterTransition - components={{ Backdrop }} + slots={{ backdrop: Backdrop }} > diff --git a/docs/data/base/components/modal/TransitionsModal.js b/docs/data/base/components/modal/TransitionsModal.js index f13565cf00ddd5..9d74b2561faf49 100644 --- a/docs/data/base/components/modal/TransitionsModal.js +++ b/docs/data/base/components/modal/TransitionsModal.js @@ -71,7 +71,7 @@ export default function TransitionsModal() { open={open} onClose={handleClose} closeAfterTransition - components={{ Backdrop }} + slots={{ backdrop: Backdrop }} > diff --git a/docs/data/base/components/modal/TransitionsModal.tsx b/docs/data/base/components/modal/TransitionsModal.tsx index 4e33897584c8ec..b81cedbc068a54 100644 --- a/docs/data/base/components/modal/TransitionsModal.tsx +++ b/docs/data/base/components/modal/TransitionsModal.tsx @@ -68,7 +68,7 @@ export default function TransitionsModal() { open={open} onClose={handleClose} closeAfterTransition - components={{ Backdrop }} + slots={{ backdrop: Backdrop }} > diff --git a/docs/data/base/components/select/UnstyledSelectControlled.js b/docs/data/base/components/select/UnstyledSelectControlled.js index 4e5a8d9cb7ad97..8e1fa5a0292cf8 100644 --- a/docs/data/base/components/select/UnstyledSelectControlled.js +++ b/docs/data/base/components/select/UnstyledSelectControlled.js @@ -138,14 +138,14 @@ const Paragraph = styled('p')( ); function CustomSelect(props) { - const components = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; } CustomSelect.propTypes = { @@ -154,10 +154,10 @@ CustomSelect.propTypes = { * Either a string to use a HTML element or a component. * @default {} */ - components: PropTypes.shape({ - Listbox: PropTypes.elementType, - Popper: PropTypes.func, - Root: PropTypes.elementType, + slots: PropTypes.shape({ + listbox: PropTypes.elementType, + popper: PropTypes.func, + root: PropTypes.elementType, }), }; diff --git a/docs/data/base/components/select/UnstyledSelectControlled.tsx b/docs/data/base/components/select/UnstyledSelectControlled.tsx index 5fca0a1b6a6bb2..d6533e84267127 100644 --- a/docs/data/base/components/select/UnstyledSelectControlled.tsx +++ b/docs/data/base/components/select/UnstyledSelectControlled.tsx @@ -140,14 +140,14 @@ const Paragraph = styled('p')( ); function CustomSelect(props: SelectUnstyledProps) { - const components: SelectUnstyledProps['components'] = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots: SelectUnstyledProps['slots'] = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; } export default function UnstyledSelectsMultiple() { diff --git a/docs/data/base/components/select/UnstyledSelectCustomRenderValue.js b/docs/data/base/components/select/UnstyledSelectCustomRenderValue.js index 2af84cf71de4ae..259f821f677fc5 100644 --- a/docs/data/base/components/select/UnstyledSelectCustomRenderValue.js +++ b/docs/data/base/components/select/UnstyledSelectCustomRenderValue.js @@ -128,14 +128,14 @@ const StyledPopper = styled(PopperUnstyled)` `; function CustomSelect(props) { - const components = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; } CustomSelect.propTypes = { @@ -144,10 +144,10 @@ CustomSelect.propTypes = { * Either a string to use a HTML element or a component. * @default {} */ - components: PropTypes.shape({ - Listbox: PropTypes.elementType, - Popper: PropTypes.func, - Root: PropTypes.elementType, + slots: PropTypes.shape({ + listbox: PropTypes.elementType, + popper: PropTypes.func, + root: PropTypes.elementType, }), }; diff --git a/docs/data/base/components/select/UnstyledSelectCustomRenderValue.tsx b/docs/data/base/components/select/UnstyledSelectCustomRenderValue.tsx index 29249c7f697fbb..d31750286b5cff 100644 --- a/docs/data/base/components/select/UnstyledSelectCustomRenderValue.tsx +++ b/docs/data/base/components/select/UnstyledSelectCustomRenderValue.tsx @@ -131,14 +131,14 @@ const StyledPopper = styled(PopperUnstyled)` `; function CustomSelect(props: SelectUnstyledProps) { - const components: SelectUnstyledProps['components'] = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots: SelectUnstyledProps['slots'] = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; } function renderValue(option: SelectOption | null) { diff --git a/docs/data/base/components/select/UnstyledSelectForm.js b/docs/data/base/components/select/UnstyledSelectForm.js index 98ee50a59b02f2..f7d470607c9a5b 100644 --- a/docs/data/base/components/select/UnstyledSelectForm.js +++ b/docs/data/base/components/select/UnstyledSelectForm.js @@ -139,14 +139,14 @@ const Label = styled('label')( ); const CustomSelect = React.forwardRef(function CustomSelect(props, ref) { - const components = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; }); export default function UnstyledSelectForm() { diff --git a/docs/data/base/components/select/UnstyledSelectForm.tsx b/docs/data/base/components/select/UnstyledSelectForm.tsx index 01ab0ed5c8000e..edec88a830b0b4 100644 --- a/docs/data/base/components/select/UnstyledSelectForm.tsx +++ b/docs/data/base/components/select/UnstyledSelectForm.tsx @@ -145,14 +145,14 @@ const CustomSelect = React.forwardRef(function CustomSelect( props: SelectUnstyledProps, ref: React.ForwardedRef, ) { - const components: SelectUnstyledProps['components'] = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots: SelectUnstyledProps['slots'] = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; }) as ( props: SelectUnstyledProps & React.RefAttributes, ) => JSX.Element; diff --git a/docs/data/base/components/select/UnstyledSelectGrouping.js b/docs/data/base/components/select/UnstyledSelectGrouping.js index 1501a4a0ae6ef3..90abb702cb5c13 100644 --- a/docs/data/base/components/select/UnstyledSelectGrouping.js +++ b/docs/data/base/components/select/UnstyledSelectGrouping.js @@ -154,14 +154,14 @@ const StyledPopper = styled(PopperUnstyled)` `; function CustomSelect(props) { - const components = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; } CustomSelect.propTypes = { @@ -170,22 +170,22 @@ CustomSelect.propTypes = { * Either a string to use a HTML element or a component. * @default {} */ - components: PropTypes.shape({ - Listbox: PropTypes.elementType, - Popper: PropTypes.func, - Root: PropTypes.elementType, + slots: PropTypes.shape({ + listbox: PropTypes.elementType, + popper: PropTypes.func, + root: PropTypes.elementType, }), }; const CustomOptionGroup = React.forwardRef(function CustomOptionGroup(props, ref) { - const components = { - Root: StyledGroupRoot, - Label: StyledGroupHeader, - List: StyledGroupOptions, - ...props.components, + const slots = { + root: StyledGroupRoot, + label: StyledGroupHeader, + list: StyledGroupOptions, + ...props.slots, }; - return ; + return ; }); CustomOptionGroup.propTypes = { @@ -194,10 +194,10 @@ CustomOptionGroup.propTypes = { * Either a string to use a HTML element or a component. * @default {} */ - components: PropTypes.shape({ - Label: PropTypes.elementType, - List: PropTypes.elementType, - Root: PropTypes.elementType, + slots: PropTypes.shape({ + label: PropTypes.elementType, + list: PropTypes.elementType, + root: PropTypes.elementType, }), }; diff --git a/docs/data/base/components/select/UnstyledSelectGrouping.tsx b/docs/data/base/components/select/UnstyledSelectGrouping.tsx index f975627add674b..6a559d27ee0e24 100644 --- a/docs/data/base/components/select/UnstyledSelectGrouping.tsx +++ b/docs/data/base/components/select/UnstyledSelectGrouping.tsx @@ -158,28 +158,28 @@ const StyledPopper = styled(PopperUnstyled)` `; function CustomSelect(props: SelectUnstyledProps) { - const components: SelectUnstyledProps['components'] = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots: SelectUnstyledProps['slots'] = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; } const CustomOptionGroup = React.forwardRef(function CustomOptionGroup( props: OptionGroupUnstyledProps, ref: React.ForwardedRef, ) { - const components: OptionGroupUnstyledProps['components'] = { - Root: StyledGroupRoot, - Label: StyledGroupHeader, - List: StyledGroupOptions, - ...props.components, + const slots: OptionGroupUnstyledProps['slots'] = { + root: StyledGroupRoot, + label: StyledGroupHeader, + list: StyledGroupOptions, + ...props.slots, }; - return ; + return ; }); export default function UnstyledSelectGrouping() { diff --git a/docs/data/base/components/select/UnstyledSelectIntroduction.js b/docs/data/base/components/select/UnstyledSelectIntroduction.js index 2ae6fce442bfd8..63d77cc40e58a1 100644 --- a/docs/data/base/components/select/UnstyledSelectIntroduction.js +++ b/docs/data/base/components/select/UnstyledSelectIntroduction.js @@ -45,16 +45,6 @@ Button.propTypes = { autoFocus: PropTypes.bool, children: PropTypes.node, className: PropTypes.string, - components: PropTypes.shape({ - Listbox: PropTypes.elementType, - Popper: PropTypes.func, - Root: PropTypes.elementType, - }), - componentsProps: PropTypes.shape({ - listbox: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - popper: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), defaultListboxOpen: PropTypes.bool, defaultValue: PropTypes.any, disabled: PropTypes.bool.isRequired, @@ -68,6 +58,16 @@ Button.propTypes = { open: PropTypes.bool.isRequired, optionStringifier: PropTypes.func, renderValue: PropTypes.func, + slotProps: PropTypes.shape({ + listbox: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + popper: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + slots: PropTypes.shape({ + listbox: PropTypes.elementType, + popper: PropTypes.func, + root: PropTypes.elementType, + }), value: PropTypes.any, }).isRequired, }; @@ -172,14 +172,14 @@ const StyledPopper = styled(PopperUnstyled)` `; const CustomSelect = React.forwardRef(function CustomSelect(props, ref) { - const components = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; }); CustomSelect.propTypes = { @@ -188,10 +188,10 @@ CustomSelect.propTypes = { * Either a string to use a HTML element or a component. * @default {} */ - components: PropTypes.shape({ - Listbox: PropTypes.elementType, - Popper: PropTypes.func, - Root: PropTypes.elementType, + slots: PropTypes.shape({ + listbox: PropTypes.elementType, + popper: PropTypes.func, + root: PropTypes.elementType, }), }; diff --git a/docs/data/base/components/select/UnstyledSelectIntroduction.tsx b/docs/data/base/components/select/UnstyledSelectIntroduction.tsx index cd7b30adc63bce..a6aed20058c968 100644 --- a/docs/data/base/components/select/UnstyledSelectIntroduction.tsx +++ b/docs/data/base/components/select/UnstyledSelectIntroduction.tsx @@ -147,14 +147,14 @@ const CustomSelect = React.forwardRef(function CustomSelect( props: SelectUnstyledProps, ref: React.ForwardedRef, ) { - const components = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; }); export default function UnstyledSelectIntroduction() { diff --git a/docs/data/base/components/select/UnstyledSelectMultiple.js b/docs/data/base/components/select/UnstyledSelectMultiple.js index 022aeaf7b15542..cdf3a1fed2b82c 100644 --- a/docs/data/base/components/select/UnstyledSelectMultiple.js +++ b/docs/data/base/components/select/UnstyledSelectMultiple.js @@ -130,26 +130,26 @@ const StyledPopper = styled(PopperUnstyled)` `; const CustomMultiSelect = React.forwardRef(function CustomMultiSelect(props, ref) { - const components = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; }); CustomMultiSelect.propTypes = { /** - * The components used for each slot inside the Select. + * The components used for each slot inside the MultiSelect. * Either a string to use a HTML element or a component. * @default {} */ - components: PropTypes.shape({ - Listbox: PropTypes.elementType, - Popper: PropTypes.func, - Root: PropTypes.elementType, + slots: PropTypes.shape({ + listbox: PropTypes.elementType, + popper: PropTypes.func, + root: PropTypes.elementType, }), }; diff --git a/docs/data/base/components/select/UnstyledSelectMultiple.tsx b/docs/data/base/components/select/UnstyledSelectMultiple.tsx index c8775c9c70b6dd..4c1ccfd6b25d67 100644 --- a/docs/data/base/components/select/UnstyledSelectMultiple.tsx +++ b/docs/data/base/components/select/UnstyledSelectMultiple.tsx @@ -134,14 +134,14 @@ const CustomMultiSelect = React.forwardRef(function CustomMultiSelect( props: MultiSelectUnstyledProps, ref: React.ForwardedRef, ) { - const components: MultiSelectUnstyledProps['components'] = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots: MultiSelectUnstyledProps['slots'] = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; }); export default function UnstyledSelectsMultiple() { diff --git a/docs/data/base/components/select/UnstyledSelectObjectValues.js b/docs/data/base/components/select/UnstyledSelectObjectValues.js index 97bfc6a06968fa..6340eeacf6f9c7 100644 --- a/docs/data/base/components/select/UnstyledSelectObjectValues.js +++ b/docs/data/base/components/select/UnstyledSelectObjectValues.js @@ -152,14 +152,14 @@ const Pre = styled('pre')( ); function CustomSelect(props) { - const components = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; } CustomSelect.propTypes = { @@ -168,10 +168,10 @@ CustomSelect.propTypes = { * Either a string to use a HTML element or a component. * @default {} */ - components: PropTypes.shape({ - Listbox: PropTypes.elementType, - Popper: PropTypes.func, - Root: PropTypes.elementType, + slots: PropTypes.shape({ + listbox: PropTypes.elementType, + popper: PropTypes.func, + root: PropTypes.elementType, }), }; diff --git a/docs/data/base/components/select/UnstyledSelectObjectValues.tsx b/docs/data/base/components/select/UnstyledSelectObjectValues.tsx index eae52ea386a2fb..775abfbee78b41 100644 --- a/docs/data/base/components/select/UnstyledSelectObjectValues.tsx +++ b/docs/data/base/components/select/UnstyledSelectObjectValues.tsx @@ -154,14 +154,14 @@ const Pre = styled('pre')( ); function CustomSelect(props: SelectUnstyledProps) { - const components: SelectUnstyledProps['components'] = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots: SelectUnstyledProps['slots'] = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; } interface Character { diff --git a/docs/data/base/components/select/UnstyledSelectObjectValuesForm.js b/docs/data/base/components/select/UnstyledSelectObjectValuesForm.js index e92a80a32bcf49..ccd615281c11aa 100644 --- a/docs/data/base/components/select/UnstyledSelectObjectValuesForm.js +++ b/docs/data/base/components/select/UnstyledSelectObjectValuesForm.js @@ -153,14 +153,14 @@ const Button = styled('button')` `; function CustomSelect(props) { - const components = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; } CustomSelect.propTypes = { @@ -169,10 +169,10 @@ CustomSelect.propTypes = { * Either a string to use a HTML element or a component. * @default {} */ - components: PropTypes.shape({ - Listbox: PropTypes.elementType, - Popper: PropTypes.func, - Root: PropTypes.elementType, + slots: PropTypes.shape({ + listbox: PropTypes.elementType, + popper: PropTypes.func, + root: PropTypes.elementType, }), }; diff --git a/docs/data/base/components/select/UnstyledSelectObjectValuesForm.tsx b/docs/data/base/components/select/UnstyledSelectObjectValuesForm.tsx index d9706da80453e0..e6424133078e92 100644 --- a/docs/data/base/components/select/UnstyledSelectObjectValuesForm.tsx +++ b/docs/data/base/components/select/UnstyledSelectObjectValuesForm.tsx @@ -156,14 +156,14 @@ const Button = styled('button')` `; function CustomSelect(props: SelectUnstyledProps) { - const components: SelectUnstyledProps['components'] = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots: SelectUnstyledProps['slots'] = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; } interface Character { diff --git a/docs/data/base/components/select/UnstyledSelectRichOptions.js b/docs/data/base/components/select/UnstyledSelectRichOptions.js index eca4484bfcc753..7cb72f8ffe833d 100644 --- a/docs/data/base/components/select/UnstyledSelectRichOptions.js +++ b/docs/data/base/components/select/UnstyledSelectRichOptions.js @@ -134,14 +134,14 @@ const StyledPopper = styled(PopperUnstyled)` `; const CustomSelect = React.forwardRef(function CustomSelect(props, ref) { - const components = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; }); CustomSelect.propTypes = { @@ -150,10 +150,10 @@ CustomSelect.propTypes = { * Either a string to use a HTML element or a component. * @default {} */ - components: PropTypes.shape({ - Listbox: PropTypes.elementType, - Popper: PropTypes.func, - Root: PropTypes.elementType, + slots: PropTypes.shape({ + listbox: PropTypes.elementType, + popper: PropTypes.func, + root: PropTypes.elementType, }), }; diff --git a/docs/data/base/components/select/UnstyledSelectRichOptions.tsx b/docs/data/base/components/select/UnstyledSelectRichOptions.tsx index 3be64c857d7b89..a718ea09765cac 100644 --- a/docs/data/base/components/select/UnstyledSelectRichOptions.tsx +++ b/docs/data/base/components/select/UnstyledSelectRichOptions.tsx @@ -139,14 +139,14 @@ const CustomSelect = React.forwardRef(function CustomSelect( props: SelectUnstyledProps, ref: React.ForwardedRef, ) { - const components: SelectUnstyledProps['components'] = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots: SelectUnstyledProps['slots'] = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; }); export default function UnstyledSelectRichOptions() { diff --git a/docs/data/base/components/select/UnstyledSelectSimple.js b/docs/data/base/components/select/UnstyledSelectSimple.js index 4ab946afae8184..d8fb59f966f702 100644 --- a/docs/data/base/components/select/UnstyledSelectSimple.js +++ b/docs/data/base/components/select/UnstyledSelectSimple.js @@ -128,14 +128,14 @@ const StyledPopper = styled(PopperUnstyled)` `; const CustomSelect = React.forwardRef(function CustomSelect(props, ref) { - const components = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; }); export default function UnstyledSelectSimple() { diff --git a/docs/data/base/components/select/UnstyledSelectSimple.tsx b/docs/data/base/components/select/UnstyledSelectSimple.tsx index 8f53d447a90526..64b67cf573fe33 100644 --- a/docs/data/base/components/select/UnstyledSelectSimple.tsx +++ b/docs/data/base/components/select/UnstyledSelectSimple.tsx @@ -134,14 +134,14 @@ const CustomSelect = React.forwardRef(function CustomSelect( props: SelectUnstyledProps, ref: React.ForwardedRef, ) { - const components: SelectUnstyledProps['components'] = { - Root: StyledButton, - Listbox: StyledListbox, - Popper: StyledPopper, - ...props.components, + const slots: SelectUnstyledProps['slots'] = { + root: StyledButton, + listbox: StyledListbox, + popper: StyledPopper, + ...props.slots, }; - return ; + return ; }) as ( props: SelectUnstyledProps & React.RefAttributes, ) => JSX.Element; diff --git a/docs/data/base/components/select/select.md b/docs/data/base/components/select/select.md index f8a4ce425acfdf..fe8eb4a4597b2c 100644 --- a/docs/data/base/components/select/select.md +++ b/docs/data/base/components/select/select.md @@ -126,27 +126,23 @@ Use the `component` prop to override the root slot with a custom element: ``` -Use the `components` prop to override any interior slots in addition to the root: +Use the `slots` prop to override any interior slots in addition to the root: ```jsx - + ``` :::warning -If the root element is customized with both the `component` and `components` props, then `component` will take precedence. +If the root element is customized with both the `component` and `slots` props, then `component` will take precedence. ::: -Use the `componentsProps` prop to pass custom props to internal slots. +Use the `slotProps` prop to pass custom props to internal slots. The following code snippet applies a CSS class called `my-listbox` to the listbox slot: ```jsx - + ``` -:::warning -Note that `componentsProps` slot names are written in lowercase (`root`) while `components` slot names are capitalized (`Root`). -::: - ## Hook ```js diff --git a/docs/data/base/components/slider/slider.md b/docs/data/base/components/slider/slider.md index 6d5c05ae24745c..4eadefc664e257 100644 --- a/docs/data/base/components/slider/slider.md +++ b/docs/data/base/components/slider/slider.md @@ -108,27 +108,23 @@ Use the `component` prop to override the root slot with a custom element: ``` -Use the `components` prop to override any interior slots in addition to the root: +Use the `slots` prop to override any interior slots in addition to the root: ```jsx - + ``` :::warning -If the root element is customized with both the `component` and `components` props, then `component` will take precedence. +If the root element is customized with both the `component` and `slots` props, then `component` will take precedence. ::: -Use the `componentsProps` prop to pass custom props to internal slots. +Use the `slotProps` prop to pass custom props to internal slots. The following code snippet applies a CSS class called `my-rail` to the rail slot: ```jsx - + ``` -:::warning -Note that `componentsProps` slot names are written in lowercase (`root`) while `components` slot names are capitalized (`Root`). -::: - ## Hook ```js diff --git a/docs/data/base/components/snackbar/snackbar.md b/docs/data/base/components/snackbar/snackbar.md index c8ed37ffb3e7e6..43e0e5c4894b2e 100644 --- a/docs/data/base/components/snackbar/snackbar.md +++ b/docs/data/base/components/snackbar/snackbar.md @@ -68,27 +68,23 @@ Use the `component` prop to override the root slot with a custom element: ``` -Use the `components` prop to override any interior slots in addition to the root: +Use the `slots` prop to override any interior slots in addition to the root: ```jsx - + ``` :::warning -If the root element is customized with both the `component` and `components` props, then `component` will take precedence. +If the root element is customized with both the `component` and `slots` props, then `component` will take precedence. ::: -Use the `componentsProps` prop to pass custom props to internal slots. +Use the `slotProps` prop to pass custom props to internal slots. The following code snippet applies a CSS class called `my-snackbar` to the root slot: ```jsx - + ``` -:::warning -Note that `componentsProps` slot names are written in lowercase (`root`) while `components` slot names are capitalized (`Root`). -::: - ## Hook ```js diff --git a/docs/data/base/components/switch/UnstyledSwitchIntroduction.js b/docs/data/base/components/switch/UnstyledSwitchIntroduction.js index 584bb8461e9748..d2e6fd91a65c18 100644 --- a/docs/data/base/components/switch/UnstyledSwitchIntroduction.js +++ b/docs/data/base/components/switch/UnstyledSwitchIntroduction.js @@ -83,7 +83,7 @@ const Root = styled('span')( ); export default function UnstyledSwitches() { - const label = { componentsProps: { input: { 'aria-label': 'Demo switch' } } }; + const label = { slotProps: { input: { 'aria-label': 'Demo switch' } } }; return (
diff --git a/docs/data/base/components/switch/UnstyledSwitchIntroduction.tsx b/docs/data/base/components/switch/UnstyledSwitchIntroduction.tsx index 584bb8461e9748..d2e6fd91a65c18 100644 --- a/docs/data/base/components/switch/UnstyledSwitchIntroduction.tsx +++ b/docs/data/base/components/switch/UnstyledSwitchIntroduction.tsx @@ -83,7 +83,7 @@ const Root = styled('span')( ); export default function UnstyledSwitches() { - const label = { componentsProps: { input: { 'aria-label': 'Demo switch' } } }; + const label = { slotProps: { input: { 'aria-label': 'Demo switch' } } }; return (
diff --git a/docs/data/base/components/switch/UnstyledSwitches.js b/docs/data/base/components/switch/UnstyledSwitches.js index 584bb8461e9748..d2e6fd91a65c18 100644 --- a/docs/data/base/components/switch/UnstyledSwitches.js +++ b/docs/data/base/components/switch/UnstyledSwitches.js @@ -83,7 +83,7 @@ const Root = styled('span')( ); export default function UnstyledSwitches() { - const label = { componentsProps: { input: { 'aria-label': 'Demo switch' } } }; + const label = { slotProps: { input: { 'aria-label': 'Demo switch' } } }; return (
diff --git a/docs/data/base/components/switch/UnstyledSwitches.tsx b/docs/data/base/components/switch/UnstyledSwitches.tsx index 584bb8461e9748..d2e6fd91a65c18 100644 --- a/docs/data/base/components/switch/UnstyledSwitches.tsx +++ b/docs/data/base/components/switch/UnstyledSwitches.tsx @@ -83,7 +83,7 @@ const Root = styled('span')( ); export default function UnstyledSwitches() { - const label = { componentsProps: { input: { 'aria-label': 'Demo switch' } } }; + const label = { slotProps: { input: { 'aria-label': 'Demo switch' } } }; return (
diff --git a/docs/data/base/components/switch/switch.md b/docs/data/base/components/switch/switch.md index 8a0f9588801751..5ee3a3f837ea9d 100644 --- a/docs/data/base/components/switch/switch.md +++ b/docs/data/base/components/switch/switch.md @@ -63,27 +63,23 @@ Use the `component` prop to override the root slot with a custom element: ``` -Use the `components` prop to override any interior slots in addition to the root: +Use the `slots` prop to override any interior slots in addition to the root: ```jsx - + ``` :::warning -If the root element is customized with both the `component` and `components` props, then `component` will take precedence. +If the root element is customized with both the `component` and `slots` props, then `component` will take precedence. ::: -Use the `componentsProps` prop to pass custom props to internal slots. +Use the `slotProps` prop to pass custom props to internal slots. The following code snippet applies a CSS class called `my-thumb` to the thumb slot: ```jsx - + ``` -:::warning -Note that `componentsProps` slot names are written in lowercase (`root`) while `components` slot names are capitalized (`Root`). -::: - ## Hook ```js diff --git a/docs/data/base/components/table-pagination/TableCustomized.js b/docs/data/base/components/table-pagination/TableCustomized.js index 795cdcecc38139..510e9786182dab 100644 --- a/docs/data/base/components/table-pagination/TableCustomized.js +++ b/docs/data/base/components/table-pagination/TableCustomized.js @@ -190,7 +190,7 @@ export default function UnstyledTable() { count={rows.length} rowsPerPage={rowsPerPage} page={page} - componentsProps={{ + slotProps={{ select: { 'aria-label': 'rows per page', }, diff --git a/docs/data/base/components/table-pagination/TableCustomized.tsx b/docs/data/base/components/table-pagination/TableCustomized.tsx index 77c17480398a4e..cd5df654b6a2b5 100644 --- a/docs/data/base/components/table-pagination/TableCustomized.tsx +++ b/docs/data/base/components/table-pagination/TableCustomized.tsx @@ -195,7 +195,7 @@ export default function UnstyledTable() { count={rows.length} rowsPerPage={rowsPerPage} page={page} - componentsProps={{ + slotProps={{ select: { 'aria-label': 'rows per page', }, diff --git a/docs/data/base/components/table-pagination/TableUnstyled.js b/docs/data/base/components/table-pagination/TableUnstyled.js index 9ffa41d56fd30d..5bf9fd25db2273 100644 --- a/docs/data/base/components/table-pagination/TableUnstyled.js +++ b/docs/data/base/components/table-pagination/TableUnstyled.js @@ -135,7 +135,7 @@ export default function UnstyledTable() { count={rows.length} rowsPerPage={rowsPerPage} page={page} - componentsProps={{ + slotProps={{ select: { 'aria-label': 'rows per page', }, diff --git a/docs/data/base/components/table-pagination/TableUnstyled.tsx b/docs/data/base/components/table-pagination/TableUnstyled.tsx index 18aa16dff05b81..37505f7e26bb00 100644 --- a/docs/data/base/components/table-pagination/TableUnstyled.tsx +++ b/docs/data/base/components/table-pagination/TableUnstyled.tsx @@ -139,7 +139,7 @@ export default function UnstyledTable() { count={rows.length} rowsPerPage={rowsPerPage} page={page} - componentsProps={{ + slotProps={{ select: { 'aria-label': 'rows per page', }, diff --git a/docs/data/base/components/table-pagination/UnstyledPaginationIntroduction.js b/docs/data/base/components/table-pagination/UnstyledPaginationIntroduction.js index 4e7dd9fab6fd8c..9fa90157e29f49 100644 --- a/docs/data/base/components/table-pagination/UnstyledPaginationIntroduction.js +++ b/docs/data/base/components/table-pagination/UnstyledPaginationIntroduction.js @@ -165,7 +165,7 @@ export default function UnstyledPaginationIntroduction() { count={rows.length} rowsPerPage={rowsPerPage} page={page} - componentsProps={{ + slotProps={{ select: { 'aria-label': 'rows per page', }, diff --git a/docs/data/base/components/table-pagination/UnstyledPaginationIntroduction.tsx b/docs/data/base/components/table-pagination/UnstyledPaginationIntroduction.tsx index 5b4a2cf9fbebfd..e56756f3a5163c 100644 --- a/docs/data/base/components/table-pagination/UnstyledPaginationIntroduction.tsx +++ b/docs/data/base/components/table-pagination/UnstyledPaginationIntroduction.tsx @@ -170,7 +170,7 @@ export default function UnstyledPaginationIntroduction() { count={rows.length} rowsPerPage={rowsPerPage} page={page} - componentsProps={{ + slotProps={{ select: { 'aria-label': 'rows per page', }, diff --git a/docs/data/base/components/table-pagination/table-pagination.md b/docs/data/base/components/table-pagination/table-pagination.md index f19d73b3348873..14b372d2130e06 100644 --- a/docs/data/base/components/table-pagination/table-pagination.md +++ b/docs/data/base/components/table-pagination/table-pagination.md @@ -18,7 +18,7 @@ It controls two properties of its parent table: - number of rows per page `TablePaginationUnstyled` renders its internal elements in a `` tag by default so it can be inserted into a table's ``. -You can use the `component` or `components.Root` prop to render a different root element—for example, if you need to place the pagination controls outside of the table. +You can use the `component` or `slots.root` prop to render a different root element—for example, if you need to place the pagination controls outside of the table. See the [Slot props section](#slot-props) for details. {{"demo": "UnstyledPaginationIntroduction.tsx", "defaultCodeOpen": false, "bg": "gradient"}} @@ -110,27 +110,23 @@ Use the `component` prop to override the root slot with a custom element: ``` -Use the `components` prop to override any interior slots in addition to the root: +Use the `slots` prop to override any interior slots in addition to the root: ```jsx - + ``` :::warning -If the root element is customized with both the `component` and `components` props, then `component` will take precedence. +If the root element is customized with both the `component` and `slots` props, then `component` will take precedence. ::: -Use the `componentsProps` prop to pass custom props to internal slots. +Use the `slotProps` prop to pass custom props to internal slots. The following code snippet applies a CSS class called `my-spacer` to the spacer slot: ```jsx - + ``` -:::warning -Note that `componentsProps` slot names are written in lowercase (`root`) while `components` slot names are capitalized (`Root`). -::: - ## Customization ### Custom pagination options diff --git a/docs/data/base/components/tabs/tabs.md b/docs/data/base/components/tabs/tabs.md index b9d5b58a76ad72..149f4f4988ccef 100644 --- a/docs/data/base/components/tabs/tabs.md +++ b/docs/data/base/components/tabs/tabs.md @@ -95,27 +95,23 @@ Use the `component` prop to override the root slot with a custom element: If you provide a non-interactive element such as a ``, the `TabUnstyled` component will automatically add the necessary accessibility attributes. -Use the `components` prop to override any interior slots in addition to the root: +Use the `slots` prop to override any interior slots in addition to the root: ```jsx - + ``` :::warning -If the root element is customized with both the `component` and `components` props, then `component` will take precedence. +If the root element is customized with both the `component` and `slots` props, then `component` will take precedence. ::: -Use the `componentsProps` prop to pass custom props to internal slots. +Use the `slotProps` prop to pass custom props to internal slots. The following code snippet applies a CSS class called `my-tab-list` to the root slot: ```jsx - + ``` -:::warning -Note that `componentsProps` slot names are written in lowercase (`root`) while `components` slot names are capitalized (`Root`). -::: - ## Customization ### Third-party routing library diff --git a/docs/data/base/getting-started/customization/StylingSlots.js b/docs/data/base/getting-started/customization/StylingSlots.js index 2e0ee2aecf2aa4..7408f64884b891 100644 --- a/docs/data/base/getting-started/customization/StylingSlots.js +++ b/docs/data/base/getting-started/customization/StylingSlots.js @@ -59,5 +59,5 @@ const Input = styled('input')` `; export default function StylingSlots() { - return ; + return ; } diff --git a/docs/data/base/getting-started/customization/StylingSlots.tsx b/docs/data/base/getting-started/customization/StylingSlots.tsx index 2e0ee2aecf2aa4..7408f64884b891 100644 --- a/docs/data/base/getting-started/customization/StylingSlots.tsx +++ b/docs/data/base/getting-started/customization/StylingSlots.tsx @@ -59,5 +59,5 @@ const Input = styled('input')` `; export default function StylingSlots() { - return ; + return ; } diff --git a/docs/data/base/getting-started/customization/StylingSlots.tsx.preview b/docs/data/base/getting-started/customization/StylingSlots.tsx.preview index 1ff0f7c6c27315..942f03ca800c9b 100644 --- a/docs/data/base/getting-started/customization/StylingSlots.tsx.preview +++ b/docs/data/base/getting-started/customization/StylingSlots.tsx.preview @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/docs/data/base/getting-started/customization/customization.md b/docs/data/base/getting-started/customization/customization.md index a24dc1700001f0..9de2bf02c97d69 100644 --- a/docs/data/base/getting-started/customization/customization.md +++ b/docs/data/base/getting-started/customization/customization.md @@ -21,21 +21,21 @@ Additionally, you can import a `[componentName]Classes` object that describes al ## Overriding subcomponent slots -If you want to make changes to a component's rendered HTML structure, you can override the default subcomponents ("slots") using the `components` and/or `component` prop—see ["Shared props" on the Base Usage page](/base/getting-started/usage/#shared-props) for more details. +If you want to make changes to a component's rendered HTML structure, you can override the default subcomponents ("slots") using the `slots` and/or `component` prop—see ["Shared props" on the Base Usage page](/base/getting-started/usage/#shared-props) for more details. -The following demo uses [SwitchUnstyled](/base/react-switch/) to show how to create a styled component by applying styles to three of its subcomponent slots: `Root`, `Thumb`, and `Input`. +The following demo uses [SwitchUnstyled](/base/react-switch/) to show how to create a styled component by applying styles to three of its subcomponent slots: `root`, `thumb`, and `input`. Note that although this demo uses [MUI System](/system/styled/) as a styling solution, you are free to choose any alternative. {{"demo": "StylingSlots.js"}} -The components you pass in the `components` prop receive the `ownerState` prop from the top-level component (the "owner"). +The components you pass in the `slots` prop receive the `ownerState` prop from the top-level component (the "owner"). By convention, it contains all props passed to the owner, merged with its rendering state. For example: ```jsx - + ``` In this case, `MyCustomThumb` component receives the `ownerState` object with the following data: diff --git a/docs/data/base/getting-started/usage/usage.md b/docs/data/base/getting-started/usage/usage.md index b7af71ceff2482..f182382274feeb 100644 --- a/docs/data/base/getting-started/usage/usage.md +++ b/docs/data/base/getting-started/usage/usage.md @@ -30,9 +30,9 @@ Base components are self-supporting and fully functional in isolation. Each component has its own unique API, but all _non-utility_ components accept the following shared props: -### components +### slots -The `components` prop is an object that lets you override any interior subcomponents—known as **slots**—of the base component itself. +The `slots` prop is an object that lets you override any interior subcomponents—known as **slots**—of the base component itself. :::info Each component contains a root slot, and other appropriate slots based on the nature of the component. @@ -42,18 +42,18 @@ For example, the `BadgeUnstyled` contains two slots: - `badge`: the badge element itself. ::: -You can use the `components` prop to override default slots with either custom components or HTML elements. +You can use the `slots` prop to override default slots with either custom components or HTML elements. For example, the [`BadgeUnstyled`](/base/react-badge/) component renders a `` by default. The code snippet below shows how to override this by assigning a `
` to the root slot: ```jsx - + ``` ### component -The (singular) `component` prop provides a shortcut to `components.Root`. +The `component` prop provides a shortcut to `slots.root`. This is useful if you are only overriding the root element of the component. The code snippet below shows how to override the root element of the [`BadgeUnstyled`](/base/react-badge/) component using the `component` prop: @@ -63,25 +63,21 @@ The code snippet below shows how to override the root element of the [`BadgeUnst ``` :::warning -If the root slot is customized with both the `component` and `components` props, then `component` will take precedence. +If the root slot is customized with both the `component` and `slots` props, then `component` will take precedence. ::: -### componentsProps +### slotProps -The `componentsProps` prop is an object that contains the props for all slots within a component. +The `slotProps` prop is an object that contains the props for all slots within a component. You can use it to define additional custom props for a component's interior elements. For example, the code snippet below shows how to add a custom CSS class to the badge slot of the `BadgeUnstyled` component: ```jsx - + ``` -:::warning -Note that `componentsProps` slot names are written in lowercase (`root`) while `components` slot names are capitalized (`Root`). -::: - -All additional props placed on the primary component are also propagated into the root slot (just as if they were placed in `componentsProps.root`). +All additional props placed on the primary component are also propagated into the root slot (just as if they were placed in `slotProps.root`). These two examples are equivalent: @@ -90,21 +86,21 @@ These two examples are equivalent: ``` ```jsx - + ``` :::warning -If both `componentsProps.root` and additional props have the same keys but different values, the `componentsProps.root` props will take precedence. +If both `slotProps.root` and additional props have the same keys but different values, the `slotProps.root` props will take precedence. This does not apply to classes or the `style` prop—they will be merged instead. ::: ### Best practices -If you are customizing a component like [`ButtonUnstyled`](/base/react-button/) that only has a root slot, you may prefer to use the more succinct `component` prop instead of `components`. +If you are customizing a component like [`ButtonUnstyled`](/base/react-button/) that only has a root slot, you may prefer to use the more succinct `component` prop instead of `slots`. Overriding with `component` lets you apply the attributes of that element directly to the root. For instance, if you replace the `ButtonUnstyled` root with an `
  • ` tag, you can add the `
  • ` attribute `value` directly to the component. -If you did the same with `components.Root`, you would need to place this attribute on the `componentsProps.root` object in order to avoid a TypeScript error. +If you did the same with `slots.root`, you would need to place this attribute on the `slotProps.root` object in order to avoid a TypeScript error. ## Components vs. hooks diff --git a/docs/data/base/guides/working-with-tailwind-css/working-with-tailwind-css.md b/docs/data/base/guides/working-with-tailwind-css/working-with-tailwind-css.md index 29d44d698f67e1..7f26fae74c3cf2 100644 --- a/docs/data/base/guides/working-with-tailwind-css/working-with-tailwind-css.md +++ b/docs/data/base/guides/working-with-tailwind-css/working-with-tailwind-css.md @@ -260,7 +260,7 @@ const Slider = React.forwardRef(function Slider( return ( ({ className: `hover:text-cyan-500 transition-colors ${ state.focusVisible ? 'outline-0 ring-2 ring-cyan-500' : '' @@ -414,7 +414,7 @@ const Button = React.forwardRef(function Button( export default Button; ``` -Note that we're using a callback for the `root` element inside `componentsProps`. +Note that we're using a callback for the `root` element inside `slotProps`. This allows us to conditionally apply utility classes if `focusVisible` is true. Now, let's replace all buttons in the initial markup with the new custom `Button` component. @@ -498,9 +498,9 @@ Some classes were slightly changed on some buttons so we have a consistent focus These are the things we covered in this guide: -✅ How to use Tailwind CSS utility classes to style MUI Base components, using the `componentsProps` prop for targeting specific slots within the component.\ +✅ How to use Tailwind CSS utility classes to style MUI Base components, using the `slotProps` prop for targeting specific slots within the component.\ ✅ How to create custom components for specific slots in more complex customization scenarios. We used the `component` prop to pass them into the parent component.\ -✅ How to apply conditional styling based on the owner component's state using a callback as value for the `componentsProps` prop. +✅ How to apply conditional styling based on the owner component's state using a callback as value for the `slotProps` prop. Get all the code used in this guide in the [MUI Base with Tailwind CSS](https://github.com/mui/material-ui/tree/master/examples/mui-base-with-tailwind-css) example project. diff --git a/docs/data/joy/getting-started/templates/email/components/Menu.tsx b/docs/data/joy/getting-started/templates/email/components/Menu.tsx index e53f6f5ecf86da..ca79d04e8080b1 100644 --- a/docs/data/joy/getting-started/templates/email/components/Menu.tsx +++ b/docs/data/joy/getting-started/templates/email/components/Menu.tsx @@ -101,8 +101,8 @@ function Menu({ open={isOpen} onClose={close} anchorEl={anchorEl} - components={{ Root: Popper, Listbox }} - componentsProps={{ root: { placement: 'bottom-end' }, listbox: { id } }} + slots={{ root: Popper, listbox: Listbox }} + slotProps={{ root: { placement: 'bottom-end' }, listbox: { id } }} > {menus.map(({ label, active, ...item }) => { const menuItem = ( diff --git a/docs/data/joy/getting-started/templates/files/components/Menu.tsx b/docs/data/joy/getting-started/templates/files/components/Menu.tsx index e53f6f5ecf86da..ca79d04e8080b1 100644 --- a/docs/data/joy/getting-started/templates/files/components/Menu.tsx +++ b/docs/data/joy/getting-started/templates/files/components/Menu.tsx @@ -101,8 +101,8 @@ function Menu({ open={isOpen} onClose={close} anchorEl={anchorEl} - components={{ Root: Popper, Listbox }} - componentsProps={{ root: { placement: 'bottom-end' }, listbox: { id } }} + slots={{ root: Popper, listbox: Listbox }} + slotProps={{ root: { placement: 'bottom-end' }, listbox: { id } }} > {menus.map(({ label, active, ...item }) => { const menuItem = ( diff --git a/docs/data/joy/getting-started/templates/team/components/Menu.tsx b/docs/data/joy/getting-started/templates/team/components/Menu.tsx index e53f6f5ecf86da..ca79d04e8080b1 100644 --- a/docs/data/joy/getting-started/templates/team/components/Menu.tsx +++ b/docs/data/joy/getting-started/templates/team/components/Menu.tsx @@ -101,8 +101,8 @@ function Menu({ open={isOpen} onClose={close} anchorEl={anchorEl} - components={{ Root: Popper, Listbox }} - componentsProps={{ root: { placement: 'bottom-end' }, listbox: { id } }} + slots={{ root: Popper, listbox: Listbox }} + slotProps={{ root: { placement: 'bottom-end' }, listbox: { id } }} > {menus.map(({ label, active, ...item }) => { const menuItem = ( diff --git a/docs/data/material/components/slider/CustomizedSlider.js b/docs/data/material/components/slider/CustomizedSlider.js index ce87bd6d16b5cb..1b089da28314a5 100644 --- a/docs/data/material/components/slider/CustomizedSlider.js +++ b/docs/data/material/components/slider/CustomizedSlider.js @@ -195,8 +195,8 @@ export default function CustomizedSlider() { Tooltip value label Airbnb (index === 0 ? 'Minimum price' : 'Maximum price')} defaultValue={[20, 40]} /> diff --git a/docs/data/material/components/slider/CustomizedSlider.tsx b/docs/data/material/components/slider/CustomizedSlider.tsx index 2eab801c4cc054..2e8463cd5b84aa 100644 --- a/docs/data/material/components/slider/CustomizedSlider.tsx +++ b/docs/data/material/components/slider/CustomizedSlider.tsx @@ -187,8 +187,8 @@ export default function CustomizedSlider() { Tooltip value label Airbnb (index === 0 ? 'Minimum price' : 'Maximum price')} defaultValue={[20, 40]} /> diff --git a/docs/data/material/guides/understand-mui-packages/understand-mui-packages.md b/docs/data/material/guides/understand-mui-packages/understand-mui-packages.md index b61ed65139b36d..9380ad60bc36b8 100644 --- a/docs/data/material/guides/understand-mui-packages/understand-mui-packages.md +++ b/docs/data/material/guides/understand-mui-packages/understand-mui-packages.md @@ -77,7 +77,7 @@ const Root = styled('span')(` `); export default function CustomSwitch() { - const label = { componentsProps: { input: { 'aria-label': 'Demo switch' } } }; + const label = { slotProps: { input: { 'aria-label': 'Demo switch' } } }; return ; } diff --git a/docs/pages/base/api/badge-unstyled.json b/docs/pages/base/api/badge-unstyled.json index fb875e462b7f6d..061394f0054ada 100644 --- a/docs/pages/base/api/badge-unstyled.json +++ b/docs/pages/base/api/badge-unstyled.json @@ -3,20 +3,20 @@ "badgeContent": { "type": { "name": "node" } }, "children": { "type": { "name": "node" } }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { "name": "shape", "description": "{ Badge?: elementType, Root?: elementType }" }, - "default": "{}" - }, - "componentsProps": { + "invisible": { "type": { "name": "bool" } }, + "max": { "type": { "name": "number" }, "default": "99" }, + "showZero": { "type": { "name": "bool" } }, + "slotProps": { "type": { "name": "shape", "description": "{ badge?: func
    | object, root?: func
    | object }" }, "default": "{}" }, - "invisible": { "type": { "name": "bool" } }, - "max": { "type": { "name": "number" }, "default": "99" }, - "showZero": { "type": { "name": "bool" } } + "slots": { + "type": { "name": "shape", "description": "{ badge?: elementType, root?: elementType }" }, + "default": "{}" + } }, "name": "BadgeUnstyled", "styles": { "classes": [], "globalClasses": {}, "name": null }, diff --git a/docs/pages/base/api/button-unstyled.json b/docs/pages/base/api/button-unstyled.json index 07a52bfb7b6ecf..0d8eb201e62173 100644 --- a/docs/pages/base/api/button-unstyled.json +++ b/docs/pages/base/api/button-unstyled.json @@ -7,16 +7,16 @@ } }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { "name": "shape", "description": "{ Root?: elementType }" }, - "default": "{}" - }, - "componentsProps": { + "disabled": { "type": { "name": "bool" } }, + "focusableWhenDisabled": { "type": { "name": "bool" } }, + "slotProps": { "type": { "name": "shape", "description": "{ root?: func
    | object }" }, "default": "{}" }, - "disabled": { "type": { "name": "bool" } }, - "focusableWhenDisabled": { "type": { "name": "bool" } } + "slots": { + "type": { "name": "shape", "description": "{ root?: elementType }" }, + "default": "{}" + } }, "name": "ButtonUnstyled", "styles": { "classes": [], "globalClasses": {}, "name": null }, diff --git a/docs/pages/base/api/form-control-unstyled.json b/docs/pages/base/api/form-control-unstyled.json index 4022e2cb279d48..2bc8014c37c3fc 100644 --- a/docs/pages/base/api/form-control-unstyled.json +++ b/docs/pages/base/api/form-control-unstyled.json @@ -2,13 +2,17 @@ "props": { "children": { "type": { "name": "union", "description": "node
    | func" } }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { "name": "shape", "description": "{ Root?: elementType }" }, - "default": "{}" - }, "disabled": { "type": { "name": "bool" } }, "error": { "type": { "name": "bool" } }, - "required": { "type": { "name": "bool" } } + "required": { "type": { "name": "bool" } }, + "slotProps": { + "type": { "name": "shape", "description": "{ root?: func
    | object }" }, + "default": "{}" + }, + "slots": { + "type": { "name": "shape", "description": "{ root?: elementType }" }, + "default": "{}" + } }, "name": "FormControlUnstyled", "styles": { "classes": [], "globalClasses": {}, "name": null }, diff --git a/docs/pages/base/api/input-unstyled.json b/docs/pages/base/api/input-unstyled.json index 5eb0a15349c681..6119f8483e4df8 100644 --- a/docs/pages/base/api/input-unstyled.json +++ b/docs/pages/base/api/input-unstyled.json @@ -4,20 +4,6 @@ "autoFocus": { "type": { "name": "bool" } }, "className": { "type": { "name": "string" } }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { - "name": "shape", - "description": "{ Input?: elementType, Root?: elementType, Textarea?: elementType }" - }, - "default": "{}" - }, - "componentsProps": { - "type": { - "name": "shape", - "description": "{ input?: func
    | object, root?: func
    | object }" - }, - "default": "{}" - }, "defaultValue": { "type": { "name": "any" } }, "disabled": { "type": { "name": "bool" } }, "endAdornment": { "type": { "name": "node" } }, @@ -31,6 +17,20 @@ "readOnly": { "type": { "name": "bool" } }, "required": { "type": { "name": "bool" } }, "rows": { "type": { "name": "number" } }, + "slotProps": { + "type": { + "name": "shape", + "description": "{ input?: func
    | object, root?: func
    | object }" + }, + "default": "{}" + }, + "slots": { + "type": { + "name": "shape", + "description": "{ input?: elementType, root?: elementType, textarea?: elementType }" + }, + "default": "{}" + }, "startAdornment": { "type": { "name": "node" } }, "type": { "type": { diff --git a/docs/pages/base/api/menu-item-unstyled.json b/docs/pages/base/api/menu-item-unstyled.json index b7e374a1c9a12a..dec6ad9cb8b796 100644 --- a/docs/pages/base/api/menu-item-unstyled.json +++ b/docs/pages/base/api/menu-item-unstyled.json @@ -1,16 +1,16 @@ { "props": { "component": { "type": { "name": "elementType" } }, - "components": { - "type": { "name": "shape", "description": "{ Root?: elementType }" }, - "default": "{}" - }, - "componentsProps": { + "disabled": { "type": { "name": "bool" } }, + "label": { "type": { "name": "string" } }, + "slotProps": { "type": { "name": "shape", "description": "{ root?: func
    | object }" }, "default": "{}" }, - "disabled": { "type": { "name": "bool" } }, - "label": { "type": { "name": "string" } } + "slots": { + "type": { "name": "shape", "description": "{ root?: elementType }" }, + "default": "{}" + } }, "name": "MenuItemUnstyled", "styles": { "classes": [], "globalClasses": {}, "name": null }, diff --git a/docs/pages/base/api/menu-unstyled.json b/docs/pages/base/api/menu-unstyled.json index 303ad885bc1268..f5dc28f0a806bd 100644 --- a/docs/pages/base/api/menu-unstyled.json +++ b/docs/pages/base/api/menu-unstyled.json @@ -8,20 +8,20 @@ } }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { "name": "shape", "description": "{ Listbox?: elementType, Root?: elementType }" }, - "default": "{}" - }, - "componentsProps": { + "keepMounted": { "type": { "name": "bool" } }, + "onClose": { "type": { "name": "func" } }, + "open": { "type": { "name": "bool" } }, + "slotProps": { "type": { "name": "shape", "description": "{ listbox?: func
    | object, root?: func
    | object }" }, "default": "{}" }, - "keepMounted": { "type": { "name": "bool" } }, - "onClose": { "type": { "name": "func" } }, - "open": { "type": { "name": "bool" } } + "slots": { + "type": { "name": "shape", "description": "{ listbox?: elementType, root?: elementType }" }, + "default": "{}" + } }, "name": "MenuUnstyled", "styles": { "classes": [], "globalClasses": {}, "name": null }, diff --git a/docs/pages/base/api/modal-unstyled.json b/docs/pages/base/api/modal-unstyled.json index 227c9436c59855..e35f1d27da241f 100644 --- a/docs/pages/base/api/modal-unstyled.json +++ b/docs/pages/base/api/modal-unstyled.json @@ -5,17 +5,6 @@ "classes": { "type": { "name": "object" } }, "closeAfterTransition": { "type": { "name": "bool" } }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { "name": "shape", "description": "{ Backdrop?: elementType, Root?: elementType }" }, - "default": "{}" - }, - "componentsProps": { - "type": { - "name": "shape", - "description": "{ backdrop?: func
    | object, root?: func
    | object }" - }, - "default": "{}" - }, "container": { "type": { "name": "union", "description": "HTML element
    | func" } }, "disableAutoFocus": { "type": { "name": "bool" } }, "disableEnforceFocus": { "type": { "name": "bool" } }, @@ -30,7 +19,18 @@ "deprecated": true, "deprecationInfo": "Use the onClose prop with the reason argument to handle the backdropClick events." }, - "onClose": { "type": { "name": "func" } } + "onClose": { "type": { "name": "func" } }, + "slotProps": { + "type": { + "name": "shape", + "description": "{ backdrop?: func
    | object, root?: func
    | object }" + }, + "default": "{}" + }, + "slots": { + "type": { "name": "shape", "description": "{ backdrop?: elementType, root?: elementType }" }, + "default": "{}" + } }, "name": "ModalUnstyled", "styles": { @@ -38,7 +38,7 @@ "globalClasses": { "root": "MuiModal-root", "hidden": "MuiModal-hidden" }, "name": null }, - "spread": true, + "spread": false, "forwardsRefTo": "HTMLDivElement", "filename": "/packages/mui-base/src/ModalUnstyled/ModalUnstyled.js", "inheritance": null, diff --git a/docs/pages/base/api/multi-select-unstyled.json b/docs/pages/base/api/multi-select-unstyled.json index f67f9ec40d70ec..061326ea2d836f 100644 --- a/docs/pages/base/api/multi-select-unstyled.json +++ b/docs/pages/base/api/multi-select-unstyled.json @@ -2,20 +2,6 @@ "props": { "autoFocus": { "type": { "name": "bool" } }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { - "name": "shape", - "description": "{ Listbox?: elementType, Popper?: elementType, Root?: elementType }" - }, - "default": "{}" - }, - "componentsProps": { - "type": { - "name": "shape", - "description": "{ listbox?: func
    | object, popper?: func
    | object, root?: func
    | object }" - }, - "default": "{}" - }, "defaultListboxOpen": { "type": { "name": "bool" } }, "defaultValue": { "type": { "name": "array" }, "default": "[]" }, "disabled": { "type": { "name": "bool" } }, @@ -27,6 +13,20 @@ "onListboxOpenChange": { "type": { "name": "func" } }, "optionStringifier": { "type": { "name": "func" }, "default": "defaultOptionStringifier" }, "renderValue": { "type": { "name": "func" } }, + "slotProps": { + "type": { + "name": "shape", + "description": "{ listbox?: func
    | object, popper?: func
    | object, root?: func
    | object }" + }, + "default": "{}" + }, + "slots": { + "type": { + "name": "shape", + "description": "{ listbox?: elementType, popper?: elementType, root?: elementType }" + }, + "default": "{}" + }, "value": { "type": { "name": "array" } } }, "name": "MultiSelectUnstyled", diff --git a/docs/pages/base/api/option-group-unstyled.json b/docs/pages/base/api/option-group-unstyled.json index 66b5035d83c456..6b2ec3fec55506 100644 --- a/docs/pages/base/api/option-group-unstyled.json +++ b/docs/pages/base/api/option-group-unstyled.json @@ -1,22 +1,22 @@ { "props": { "component": { "type": { "name": "elementType" } }, - "components": { + "disabled": { "type": { "name": "bool" } }, + "label": { "type": { "name": "node" } }, + "slotProps": { "type": { "name": "shape", - "description": "{ Label?: elementType, List?: elementType, Root?: elementType }" + "description": "{ label?: func
    | object, list?: func
    | object, root?: func
    | object }" }, "default": "{}" }, - "componentsProps": { + "slots": { "type": { "name": "shape", - "description": "{ label?: func
    | object, list?: func
    | object, root?: func
    | object }" + "description": "{ label?: elementType, list?: elementType, root?: elementType }" }, "default": "{}" - }, - "disabled": { "type": { "name": "bool" } }, - "label": { "type": { "name": "node" } } + } }, "name": "OptionGroupUnstyled", "styles": { "classes": [], "globalClasses": {}, "name": null }, diff --git a/docs/pages/base/api/option-unstyled.json b/docs/pages/base/api/option-unstyled.json index 0522551e49624a..c8692f2ec55735 100644 --- a/docs/pages/base/api/option-unstyled.json +++ b/docs/pages/base/api/option-unstyled.json @@ -2,16 +2,16 @@ "props": { "value": { "type": { "name": "any" }, "required": true }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { "name": "shape", "description": "{ Root?: elementType }" }, - "default": "{}" - }, - "componentsProps": { + "disabled": { "type": { "name": "bool" } }, + "label": { "type": { "name": "string" } }, + "slotProps": { "type": { "name": "shape", "description": "{ root?: func
    | object }" }, "default": "{}" }, - "disabled": { "type": { "name": "bool" } }, - "label": { "type": { "name": "string" } } + "slots": { + "type": { "name": "shape", "description": "{ root?: elementType }" }, + "default": "{}" + } }, "name": "OptionUnstyled", "styles": { "classes": [], "globalClasses": {}, "name": null }, diff --git a/docs/pages/base/api/popper-unstyled.json b/docs/pages/base/api/popper-unstyled.json index cde7092cee4299..0ee65d6280ab9e 100644 --- a/docs/pages/base/api/popper-unstyled.json +++ b/docs/pages/base/api/popper-unstyled.json @@ -8,14 +8,6 @@ } }, "children": { "type": { "name": "union", "description": "node
    | func" } }, - "components": { - "type": { "name": "shape", "description": "{ Root?: elementType }" }, - "default": "{}" - }, - "componentsProps": { - "type": { "name": "shape", "description": "{ root?: func
    | object }" }, - "default": "{}" - }, "container": { "type": { "name": "union", "description": "HTML element
    | func" } }, "direction": { "type": { "name": "enum", "description": "'ltr'
    | 'rtl'" }, @@ -44,11 +36,19 @@ "default": "{}" }, "popperRef": { "type": { "name": "custom", "description": "ref" } }, + "slotProps": { + "type": { "name": "shape", "description": "{ root?: func
    | object }" }, + "default": "{}" + }, + "slots": { + "type": { "name": "shape", "description": "{ root?: elementType }" }, + "default": "{}" + }, "transition": { "type": { "name": "bool" } } }, "name": "PopperUnstyled", "styles": { "classes": [], "globalClasses": {}, "name": null }, - "spread": true, + "spread": false, "forwardsRefTo": "HTMLDivElement", "filename": "/packages/mui-base/src/PopperUnstyled/PopperUnstyled.js", "inheritance": null, diff --git a/docs/pages/base/api/select-unstyled.json b/docs/pages/base/api/select-unstyled.json index ac8e2153302b40..19ce9d2148f620 100644 --- a/docs/pages/base/api/select-unstyled.json +++ b/docs/pages/base/api/select-unstyled.json @@ -2,20 +2,6 @@ "props": { "autoFocus": { "type": { "name": "bool" } }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { - "name": "shape", - "description": "{ Listbox?: elementType, Popper?: elementType, Root?: elementType }" - }, - "default": "{}" - }, - "componentsProps": { - "type": { - "name": "shape", - "description": "{ listbox?: func
    | object, popper?: func
    | object, root?: func
    | object }" - }, - "default": "{}" - }, "defaultListboxOpen": { "type": { "name": "bool" } }, "defaultValue": { "type": { "name": "any" } }, "disabled": { "type": { "name": "bool" } }, @@ -27,6 +13,20 @@ "onListboxOpenChange": { "type": { "name": "func" } }, "optionStringifier": { "type": { "name": "func" }, "default": "defaultOptionStringifier" }, "renderValue": { "type": { "name": "func" } }, + "slotProps": { + "type": { + "name": "shape", + "description": "{ listbox?: func
    | object, popper?: func
    | object, root?: func
    | object }" + }, + "default": "{}" + }, + "slots": { + "type": { + "name": "shape", + "description": "{ listbox?: elementType, popper?: elementType, root?: elementType }" + }, + "default": "{}" + }, "value": { "type": { "name": "any" } } }, "name": "SelectUnstyled", diff --git a/docs/pages/base/api/slider-unstyled.json b/docs/pages/base/api/slider-unstyled.json index aeaa1eadc95652..810e019f824f42 100644 --- a/docs/pages/base/api/slider-unstyled.json +++ b/docs/pages/base/api/slider-unstyled.json @@ -5,20 +5,6 @@ "aria-valuetext": { "type": { "name": "custom", "description": "string" } }, "classes": { "type": { "name": "object" } }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { - "name": "shape", - "description": "{ Input?: elementType, Mark?: elementType, MarkLabel?: elementType, Rail?: elementType, Root?: elementType, Thumb?: elementType, Track?: elementType, ValueLabel?: elementType }" - }, - "default": "{}" - }, - "componentsProps": { - "type": { - "name": "shape", - "description": "{ input?: func
    | object, mark?: func
    | object, markLabel?: func
    | object, rail?: func
    | object, root?: func
    | object, thumb?: func
    | object, track?: func
    | object, valueLabel?: func
    | { children?: element, className?: string, components?: { Root?: elementType }, open?: bool, style?: object, value?: number, valueLabelDisplay?: 'auto'
    | 'off'
    | 'on' } }" - }, - "default": "{}" - }, "defaultValue": { "type": { "name": "union", "description": "Array<number>
    | number" } }, @@ -44,6 +30,20 @@ "default": "'horizontal'" }, "scale": { "type": { "name": "func" }, "default": "(x) => x" }, + "slotProps": { + "type": { + "name": "shape", + "description": "{ input?: func
    | object, mark?: func
    | object, markLabel?: func
    | object, rail?: func
    | object, root?: func
    | object, thumb?: func
    | object, track?: func
    | object, valueLabel?: func
    | { children?: element, className?: string, open?: bool, style?: object, value?: number, valueLabelDisplay?: 'auto'
    | 'off'
    | 'on' } }" + }, + "default": "{}" + }, + "slots": { + "type": { + "name": "shape", + "description": "{ input?: elementType, mark?: elementType, markLabel?: elementType, rail?: elementType, root?: elementType, thumb?: elementType, track?: elementType, valueLabel?: elementType }" + }, + "default": "{}" + }, "step": { "type": { "name": "number" }, "default": "1" }, "tabIndex": { "type": { "name": "number" } }, "track": { diff --git a/docs/pages/base/api/snackbar-unstyled.json b/docs/pages/base/api/snackbar-unstyled.json index 24cb9c021f6890..cc9d38356f94df 100644 --- a/docs/pages/base/api/snackbar-unstyled.json +++ b/docs/pages/base/api/snackbar-unstyled.json @@ -2,22 +2,22 @@ "props": { "autoHideDuration": { "type": { "name": "number" }, "default": "null" }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { "name": "shape", "description": "{ Root?: elementType }" }, - "default": "{}" - }, - "componentsProps": { + "disableWindowBlurListener": { "type": { "name": "bool" } }, + "exited": { "type": { "name": "bool" }, "default": "true" }, + "onClose": { "type": { "name": "func" } }, + "open": { "type": { "name": "bool" } }, + "resumeHideDuration": { "type": { "name": "number" } }, + "slotProps": { "type": { "name": "shape", "description": "{ clickAwayListener?: func
    | { children: element, disableReactTree?: bool, mouseEvent?: 'onClick'
    | 'onMouseDown'
    | 'onMouseUp'
    | 'onPointerDown'
    | 'onPointerUp'
    | false, onClickAway?: func, touchEvent?: 'onTouchEnd'
    | 'onTouchStart'
    | false }, root?: func
    | object }" }, "default": "{}" }, - "disableWindowBlurListener": { "type": { "name": "bool" } }, - "exited": { "type": { "name": "bool" }, "default": "true" }, - "onClose": { "type": { "name": "func" } }, - "open": { "type": { "name": "bool" } }, - "resumeHideDuration": { "type": { "name": "number" } } + "slots": { + "type": { "name": "shape", "description": "{ root?: elementType }" }, + "default": "{}" + } }, "name": "SnackbarUnstyled", "styles": { "classes": [], "globalClasses": {}, "name": null }, diff --git a/docs/pages/base/api/switch-unstyled.json b/docs/pages/base/api/switch-unstyled.json index 8671dd4bc8fa7e..032fdade07dbba 100644 --- a/docs/pages/base/api/switch-unstyled.json +++ b/docs/pages/base/api/switch-unstyled.json @@ -2,25 +2,25 @@ "props": { "checked": { "type": { "name": "bool" } }, "component": { "type": { "name": "elementType" } }, - "components": { + "defaultChecked": { "type": { "name": "bool" } }, + "disabled": { "type": { "name": "bool" } }, + "onChange": { "type": { "name": "func" } }, + "readOnly": { "type": { "name": "bool" } }, + "required": { "type": { "name": "bool" } }, + "slotProps": { "type": { "name": "shape", - "description": "{ Input?: elementType, Root?: elementType, Thumb?: elementType, Track?: elementType
    | null }" + "description": "{ input?: func
    | object, root?: func
    | object, thumb?: func
    | object, track?: func
    | object }" }, "default": "{}" }, - "componentsProps": { + "slots": { "type": { "name": "shape", - "description": "{ input?: func
    | object, root?: func
    | object, thumb?: func
    | object, track?: func
    | object }" + "description": "{ input?: elementType, root?: elementType, thumb?: elementType, track?: elementType
    | null }" }, "default": "{}" - }, - "defaultChecked": { "type": { "name": "bool" } }, - "disabled": { "type": { "name": "bool" } }, - "onChange": { "type": { "name": "func" } }, - "readOnly": { "type": { "name": "bool" } }, - "required": { "type": { "name": "bool" } } + } }, "name": "SwitchUnstyled", "styles": { "classes": [], "globalClasses": {}, "name": null }, diff --git a/docs/pages/base/api/tab-panel-unstyled.json b/docs/pages/base/api/tab-panel-unstyled.json index 474b94205063eb..848332b3428564 100644 --- a/docs/pages/base/api/tab-panel-unstyled.json +++ b/docs/pages/base/api/tab-panel-unstyled.json @@ -6,12 +6,12 @@ }, "children": { "type": { "name": "node" } }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { "name": "shape", "description": "{ Root?: elementType }" }, + "slotProps": { + "type": { "name": "shape", "description": "{ root?: func
    | object }" }, "default": "{}" }, - "componentsProps": { - "type": { "name": "shape", "description": "{ root?: func
    | object }" }, + "slots": { + "type": { "name": "shape", "description": "{ root?: elementType }" }, "default": "{}" } }, diff --git a/docs/pages/base/api/tab-unstyled.json b/docs/pages/base/api/tab-unstyled.json index 19b49de1f2547d..9ea5db19aa392d 100644 --- a/docs/pages/base/api/tab-unstyled.json +++ b/docs/pages/base/api/tab-unstyled.json @@ -7,16 +7,16 @@ } }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { "name": "shape", "description": "{ Root?: elementType }" }, + "disabled": { "type": { "name": "bool" } }, + "onChange": { "type": { "name": "func" } }, + "slotProps": { + "type": { "name": "shape", "description": "{ root?: func
    | object }" }, "default": "{}" }, - "componentsProps": { - "type": { "name": "shape", "description": "{ root?: func
    | object }" }, + "slots": { + "type": { "name": "shape", "description": "{ root?: elementType }" }, "default": "{}" }, - "disabled": { "type": { "name": "bool" } }, - "onChange": { "type": { "name": "func" } }, "value": { "type": { "name": "union", "description": "number
    | string" } } }, "name": "TabUnstyled", diff --git a/docs/pages/base/api/table-pagination-unstyled.json b/docs/pages/base/api/table-pagination-unstyled.json index c8b2f3058ca8d6..407ca4bc086f4a 100644 --- a/docs/pages/base/api/table-pagination-unstyled.json +++ b/docs/pages/base/api/table-pagination-unstyled.json @@ -5,20 +5,6 @@ "page": { "type": { "name": "custom", "description": "integer" }, "required": true }, "rowsPerPage": { "type": { "name": "custom", "description": "integer" }, "required": true }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { - "name": "shape", - "description": "{ Actions?: elementType, DisplayedRows?: elementType, MenuItem?: elementType, Root?: elementType, Select?: elementType, SelectLabel?: elementType, Spacer?: elementType, Toolbar?: elementType }" - }, - "default": "{}" - }, - "componentsProps": { - "type": { - "name": "shape", - "description": "{ actions?: func
    | object, displayedRows?: func
    | object, menuItem?: func
    | object, root?: func
    | object, select?: func
    | object, selectLabel?: func
    | object, spacer?: func
    | object, toolbar?: func
    | object }" - }, - "default": "{}" - }, "getItemAriaLabel": { "type": { "name": "func" }, "default": "function defaultGetAriaLabel(type: ItemAriaLabelType) {\n return `Go to ${type} page`;\n}" @@ -37,7 +23,21 @@ }, "default": "[10, 25, 50, 100]" }, - "selectId": { "type": { "name": "string" } } + "selectId": { "type": { "name": "string" } }, + "slotProps": { + "type": { + "name": "shape", + "description": "{ actions?: func
    | object, displayedRows?: func
    | object, menuItem?: func
    | object, root?: func
    | object, select?: func
    | object, selectLabel?: func
    | object, spacer?: func
    | object, toolbar?: func
    | object }" + }, + "default": "{}" + }, + "slots": { + "type": { + "name": "shape", + "description": "{ actions?: elementType, displayedRows?: elementType, menuItem?: elementType, root?: elementType, select?: elementType, selectLabel?: elementType, spacer?: elementType, toolbar?: elementType }" + }, + "default": "{}" + } }, "name": "TablePaginationUnstyled", "styles": { "classes": [], "globalClasses": {}, "name": null }, diff --git a/docs/pages/base/api/tabs-list-unstyled.json b/docs/pages/base/api/tabs-list-unstyled.json index 402177ad8abd29..f536e262a925da 100644 --- a/docs/pages/base/api/tabs-list-unstyled.json +++ b/docs/pages/base/api/tabs-list-unstyled.json @@ -2,12 +2,12 @@ "props": { "children": { "type": { "name": "node" } }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { "name": "shape", "description": "{ Root?: elementType }" }, + "slotProps": { + "type": { "name": "shape", "description": "{ root?: func
    | object }" }, "default": "{}" }, - "componentsProps": { - "type": { "name": "shape", "description": "{ root?: func
    | object }" }, + "slots": { + "type": { "name": "shape", "description": "{ root?: elementType }" }, "default": "{}" } }, diff --git a/docs/pages/base/api/tabs-unstyled.json b/docs/pages/base/api/tabs-unstyled.json index 7aa36292f89796..bf0879d6854519 100644 --- a/docs/pages/base/api/tabs-unstyled.json +++ b/docs/pages/base/api/tabs-unstyled.json @@ -2,14 +2,6 @@ "props": { "children": { "type": { "name": "node" } }, "component": { "type": { "name": "elementType" } }, - "components": { - "type": { "name": "shape", "description": "{ Root?: elementType }" }, - "default": "{}" - }, - "componentsProps": { - "type": { "name": "shape", "description": "{ root?: func
    | object }" }, - "default": "{}" - }, "defaultValue": { "type": { "name": "union", @@ -26,6 +18,14 @@ "default": "'horizontal'" }, "selectionFollowsFocus": { "type": { "name": "bool" } }, + "slotProps": { + "type": { "name": "shape", "description": "{ root?: func
    | object }" }, + "default": "{}" + }, + "slots": { + "type": { "name": "shape", "description": "{ root?: elementType }" }, + "default": "{}" + }, "value": { "type": { "name": "union", diff --git a/docs/pages/material-ui/api/badge.json b/docs/pages/material-ui/api/badge.json index bc5f4d17533e06..88177f01071f33 100644 --- a/docs/pages/material-ui/api/badge.json +++ b/docs/pages/material-ui/api/badge.json @@ -36,6 +36,17 @@ "default": "'rectangular'" }, "showZero": { "type": { "name": "bool" } }, + "slotProps": { + "type": { + "name": "shape", + "description": "{ badge?: func
    | object, root?: func
    | object }" + }, + "default": "{}" + }, + "slots": { + "type": { "name": "shape", "description": "{ badge?: elementType, root?: elementType }" }, + "default": "{}" + }, "sx": { "type": { "name": "union", diff --git a/docs/pages/material-ui/api/dialog.json b/docs/pages/material-ui/api/dialog.json index 764060975194ba..53ab57bb4ab70d 100644 --- a/docs/pages/material-ui/api/dialog.json +++ b/docs/pages/material-ui/api/dialog.json @@ -7,7 +7,7 @@ "type": { "name": "elementType" }, "default": "styled(Backdrop, {\n name: 'MuiModal',\n slot: 'Backdrop',\n overridesResolver: (props, styles) => {\n return styles.backdrop;\n },\n})({\n zIndex: -1,\n})", "deprecated": true, - "deprecationInfo": "Use components.Backdrop instead. While this prop currently works, it will be removed in the next major version." + "deprecationInfo": "Use slots.backdrop instead. While this prop currently works, it will be removed in the next major version." }, "children": { "type": { "name": "node" } }, "classes": { "type": { "name": "object" } }, diff --git a/docs/pages/material-ui/api/modal.json b/docs/pages/material-ui/api/modal.json index ae5607deff64a7..8c6962e0b71e9f 100644 --- a/docs/pages/material-ui/api/modal.json +++ b/docs/pages/material-ui/api/modal.json @@ -6,12 +6,12 @@ "type": { "name": "elementType" }, "default": "styled(Backdrop, {\n name: 'MuiModal',\n slot: 'Backdrop',\n overridesResolver: (props, styles) => {\n return styles.backdrop;\n },\n})({\n zIndex: -1,\n})", "deprecated": true, - "deprecationInfo": "Use components.Backdrop instead. While this prop currently works, it will be removed in the next major version." + "deprecationInfo": "Use slots.backdrop instead. While this prop currently works, it will be removed in the next major version." }, "BackdropProps": { "type": { "name": "object" }, "deprecated": true, - "deprecationInfo": "Use componentsProps.backdrop instead." + "deprecationInfo": "Use slotProps.backdrop instead." }, "classes": { "type": { "name": "object" } }, "closeAfterTransition": { "type": { "name": "bool" } }, @@ -42,6 +42,17 @@ "deprecationInfo": "Use the onClose prop with the reason argument to handle the backdropClick events." }, "onClose": { "type": { "name": "func" } }, + "slotProps": { + "type": { + "name": "shape", + "description": "{ backdrop?: func
    | object, root?: func
    | object }" + }, + "default": "{}" + }, + "slots": { + "type": { "name": "shape", "description": "{ backdrop?: elementType, root?: elementType }" }, + "default": "{}" + }, "sx": { "type": { "name": "union", diff --git a/docs/pages/material-ui/api/popper.json b/docs/pages/material-ui/api/popper.json index 169ceee408c73f..c37e718ae6ef1d 100644 --- a/docs/pages/material-ui/api/popper.json +++ b/docs/pages/material-ui/api/popper.json @@ -40,6 +40,10 @@ "default": "{}" }, "popperRef": { "type": { "name": "custom", "description": "ref" } }, + "slotProps": { + "type": { "name": "shape", "description": "{ root?: func
    | object }" } + }, + "slots": { "type": { "name": "shape", "description": "{ root?: elementType }" } }, "sx": { "type": { "name": "union", diff --git a/docs/pages/material-ui/api/slider.json b/docs/pages/material-ui/api/slider.json index 02e4e0aad21685..8c9640fb9ec2b9 100644 --- a/docs/pages/material-ui/api/slider.json +++ b/docs/pages/material-ui/api/slider.json @@ -18,13 +18,6 @@ }, "default": "{}" }, - "componentsProps": { - "type": { - "name": "shape", - "description": "{ input?: func
    | object, mark?: func
    | object, markLabel?: func
    | object, rail?: func
    | object, root?: func
    | object, thumb?: func
    | object, track?: func
    | object, valueLabel?: func
    | { children?: element, className?: string, components?: { Root?: elementType }, open?: bool, style?: object, value?: number, valueLabelDisplay?: 'auto'
    | 'off'
    | 'on' } }" - }, - "default": "{}" - }, "defaultValue": { "type": { "name": "union", "description": "Array<number>
    | number" } }, @@ -57,6 +50,20 @@ }, "default": "'medium'" }, + "slotProps": { + "type": { + "name": "shape", + "description": "{ input?: func
    | object, mark?: func
    | object, markLabel?: func
    | object, rail?: func
    | object, root?: func
    | object, thumb?: func
    | object, track?: func
    | object, valueLabel?: func
    | { children?: element, className?: string, open?: bool, style?: object, value?: number, valueLabelDisplay?: 'auto'
    | 'off'
    | 'on' } }" + }, + "default": "{}" + }, + "slots": { + "type": { + "name": "shape", + "description": "{ input?: elementType, mark?: elementType, markLabel?: elementType, rail?: elementType, root?: elementType, thumb?: elementType, track?: elementType, valueLabel?: elementType }" + }, + "default": "{}" + }, "step": { "type": { "name": "number" }, "default": "1" }, "sx": { "type": { diff --git a/docs/public/static/error-codes.json b/docs/public/static/error-codes.json index b0394701d5c27c..0cc6f9b9a9db27 100644 --- a/docs/public/static/error-codes.json +++ b/docs/public/static/error-codes.json @@ -15,7 +15,7 @@ "14": "MUI: makeStyles is no longer exported from @mui/material/styles.\nYou have to import it from @mui/styles.\nSee https://mui.com/r/migration-v4/#mui-material-styles for more details.", "15": "MUI: withStyles is no longer exported from @mui/material/styles.\nYou have to import it from @mui/styles.\nSee https://mui.com/r/migration-v4/#mui-material-styles for more details.", "16": "MUI: withTheme is no longer exported from @mui/material/styles.\nYou have to import it from @mui/styles.\nSee https://mui.com/r/migration-v4/#mui-material-styles for more details.", - "17": "MUI: Expected valid input target. Did you use a custom `components.Input` and forget to forward refs? See https://mui.com/r/input-component-ref-interface for more info.", + "17": "MUI: Expected valid input target. Did you use a custom `slots.input` and forget to forward refs? See https://mui.com/r/input-component-ref-interface for more info.", "18": "MUI: `vars` is a private field used for CSS variables support.\nPlease use another name.", "19": "MUI: `useColorScheme` must be called under " } diff --git a/docs/src/components/x-grid/EditProgress.tsx b/docs/src/components/x-grid/EditProgress.tsx index 63a491f817ab21..387651b0d5c48b 100644 --- a/docs/src/components/x-grid/EditProgress.tsx +++ b/docs/src/components/x-grid/EditProgress.tsx @@ -85,8 +85,8 @@ export default function EditProgress(props: GridRenderEditCellParams) { max={1} step={0.00001} onChange={handleChange} - components={{ - ValueLabel: ValueLabelComponent, + slots={{ + valueLabel: ValueLabelComponent, }} valueLabelDisplay="auto" valueLabelFormat={(newValue) => `${(newValue * 100).toLocaleString()} %`} diff --git a/docs/translations/api-docs/badge-unstyled/badge-unstyled.json b/docs/translations/api-docs/badge-unstyled/badge-unstyled.json index dace81cd66002f..23a0e8bd8e000d 100644 --- a/docs/translations/api-docs/badge-unstyled/badge-unstyled.json +++ b/docs/translations/api-docs/badge-unstyled/badge-unstyled.json @@ -4,11 +4,11 @@ "badgeContent": "The content rendered within the badge.", "children": "The badge will be added relative to this node.", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the Badge. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Badge.", "invisible": "If true, the badge is invisible.", "max": "Max count to show.", - "showZero": "Controls whether the badge is hidden when badgeContent is zero." + "showZero": "Controls whether the badge is hidden when badgeContent is zero.", + "slotProps": "The props used for each slot inside the Badge.", + "slots": "The components used for each slot inside the Badge. Either a string to use a HTML element or a component." }, "classDescriptions": {} } diff --git a/docs/translations/api-docs/badge/badge.json b/docs/translations/api-docs/badge/badge.json index b57963a87cff53..a6fb42f6a85033 100644 --- a/docs/translations/api-docs/badge/badge.json +++ b/docs/translations/api-docs/badge/badge.json @@ -13,6 +13,8 @@ "max": "Max count to show.", "overlap": "Wrapped shape the badge should overlap.", "showZero": "Controls whether the badge is hidden when badgeContent is zero.", + "slotProps": "The props used for each slot inside the Badge.", + "slots": "The components used for each slot inside the Badge. Either a string to use a HTML element or a component.", "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.", "variant": "The variant to use." }, diff --git a/docs/translations/api-docs/button-unstyled/button-unstyled.json b/docs/translations/api-docs/button-unstyled/button-unstyled.json index 8f2ab295bdfd23..3d9dac3c5137bc 100644 --- a/docs/translations/api-docs/button-unstyled/button-unstyled.json +++ b/docs/translations/api-docs/button-unstyled/button-unstyled.json @@ -3,10 +3,10 @@ "propDescriptions": { "action": "A ref for imperative actions. It currently only supports focusVisible() action.", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the Button. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Button.", "disabled": "If true, the component is disabled.", - "focusableWhenDisabled": "If true, allows a disabled button to receive focus." + "focusableWhenDisabled": "If true, allows a disabled button to receive focus.", + "slotProps": "The props used for each slot inside the Button.", + "slots": "The components used for each slot inside the Button. Either a string to use a HTML element or a component." }, "classDescriptions": {} } diff --git a/docs/translations/api-docs/form-control-unstyled/form-control-unstyled.json b/docs/translations/api-docs/form-control-unstyled/form-control-unstyled.json index d8fa4c79da1fd0..9f37b05e4766c6 100644 --- a/docs/translations/api-docs/form-control-unstyled/form-control-unstyled.json +++ b/docs/translations/api-docs/form-control-unstyled/form-control-unstyled.json @@ -3,10 +3,11 @@ "propDescriptions": { "children": "The content of the component.", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the FormControl. Either a string to use a HTML element or a component.", "disabled": "If true, the label, input and helper text should be displayed in a disabled state.", "error": "If true, the label is displayed in an error state.", - "required": "If true, the label will indicate that the input is required." + "required": "If true, the label will indicate that the input is required.", + "slotProps": "The props used for each slot inside the FormControl.", + "slots": "The components used for each slot inside the FormControl. Either a string to use a HTML element or a component." }, "classDescriptions": {} } diff --git a/docs/translations/api-docs/input-unstyled/input-unstyled.json b/docs/translations/api-docs/input-unstyled/input-unstyled.json index 65866718b4664a..6ae799f39b1dcd 100644 --- a/docs/translations/api-docs/input-unstyled/input-unstyled.json +++ b/docs/translations/api-docs/input-unstyled/input-unstyled.json @@ -5,8 +5,6 @@ "autoFocus": "If true, the input element is focused during the first mount.", "className": "Class name applied to the root element.", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the InputBase. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Input.", "defaultValue": "The default value. Use when the component is not controlled.", "disabled": "If true, the component is disabled. The prop defaults to the value (false) inherited from the parent FormControl component.", "endAdornment": "Trailing adornment for this input.", @@ -20,6 +18,8 @@ "readOnly": "It prevents the user from changing the value of the field (not from interacting with the field).", "required": "If true, the input element is required. The prop defaults to the value (false) inherited from the parent FormControl component.", "rows": "Number of rows to display when multiline option is set to true.", + "slotProps": "The props used for each slot inside the Input.", + "slots": "The components used for each slot inside the InputBase. Either a string to use a HTML element or a component.", "startAdornment": "Leading adornment for this input.", "type": "Type of the input element. It should be a valid HTML5 input type.", "value": "The value of the input element, required for a controlled component." diff --git a/docs/translations/api-docs/menu-item-unstyled/menu-item-unstyled.json b/docs/translations/api-docs/menu-item-unstyled/menu-item-unstyled.json index 937bc601cc8183..77bc3e29834c24 100644 --- a/docs/translations/api-docs/menu-item-unstyled/menu-item-unstyled.json +++ b/docs/translations/api-docs/menu-item-unstyled/menu-item-unstyled.json @@ -2,10 +2,10 @@ "componentDescription": "", "propDescriptions": { "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the MenuItem. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the MenuItem.", "disabled": "If true, the menu item will be disabled.", - "label": "A text representation of the menu item's content. Used for keyboard text navigation matching." + "label": "A text representation of the menu item's content. Used for keyboard text navigation matching.", + "slotProps": "The props used for each slot inside the MenuItem.", + "slots": "The components used for each slot inside the MenuItem. Either a string to use a HTML element or a component." }, "classDescriptions": {} } diff --git a/docs/translations/api-docs/menu-unstyled/menu-unstyled.json b/docs/translations/api-docs/menu-unstyled/menu-unstyled.json index 51f04d80fbf113..f12a39d0952b2a 100644 --- a/docs/translations/api-docs/menu-unstyled/menu-unstyled.json +++ b/docs/translations/api-docs/menu-unstyled/menu-unstyled.json @@ -4,11 +4,11 @@ "actions": "A ref with imperative actions. It allows to select the first or last menu item.", "anchorEl": "An HTML element, virtualElement, or a function that returns either. It's used to set the position of the popper.", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the Menu. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Menu.", "keepMounted": "Always keep the menu in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Menu.", "onClose": "Triggered when focus leaves the menu and the menu should close.", - "open": "Controls whether the menu is displayed." + "open": "Controls whether the menu is displayed.", + "slotProps": "The props used for each slot inside the Menu.", + "slots": "The components used for each slot inside the Menu. Either a string to use a HTML element or a component." }, "classDescriptions": {} } diff --git a/docs/translations/api-docs/modal-unstyled/modal-unstyled.json b/docs/translations/api-docs/modal-unstyled/modal-unstyled.json index d97929a770db50..e4fc4613503b3d 100644 --- a/docs/translations/api-docs/modal-unstyled/modal-unstyled.json +++ b/docs/translations/api-docs/modal-unstyled/modal-unstyled.json @@ -5,8 +5,6 @@ "classes": "Override or extend the styles applied to the component. See CSS API below for more details.", "closeAfterTransition": "When set to true the Modal waits until a nested Transition is completed before closing.", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the Modal. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Modal.", "container": "An HTML element or function that returns one. The container will have the portal children appended to it.
    By default, it uses the body of the top-level document object, so it's simply document.body most of the time.", "disableAutoFocus": "If true, the modal will not automatically shift focus to itself when it opens, and replace it to the last focused element when it closes. This also works correctly with any modal children that have the disableAutoFocus prop.
    Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", "disableEnforceFocus": "If true, the modal will not prevent focus from leaving the modal while open.
    Generally this should never be set to true as it makes the modal less accessible to assistive technologies, like screen readers.", @@ -18,7 +16,9 @@ "keepMounted": "Always keep the children in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Modal.", "onBackdropClick": "Callback fired when the backdrop is clicked.", "onClose": "Callback fired when the component requests to be closed. The reason parameter can optionally be used to control the response to onClose.

    Signature:
    function(event: object, reason: string) => void
    event: The event source of the callback.
    reason: Can be: "escapeKeyDown", "backdropClick".", - "open": "If true, the component is shown." + "open": "If true, the component is shown.", + "slotProps": "The props used for each slot inside the Modal.", + "slots": "The components used for each slot inside the Modal. Either a string to use a HTML element or a component." }, "classDescriptions": { "root": { "description": "Styles applied to the root element." }, diff --git a/docs/translations/api-docs/modal/modal.json b/docs/translations/api-docs/modal/modal.json index 868b0512b1d8a3..ea3a9e058cb046 100644 --- a/docs/translations/api-docs/modal/modal.json +++ b/docs/translations/api-docs/modal/modal.json @@ -21,6 +21,8 @@ "onBackdropClick": "Callback fired when the backdrop is clicked.", "onClose": "Callback fired when the component requests to be closed. The reason parameter can optionally be used to control the response to onClose.

    Signature:
    function(event: object, reason: string) => void
    event: The event source of the callback.
    reason: Can be: "escapeKeyDown", "backdropClick".", "open": "If true, the component is shown.", + "slotProps": "The props used for each slot inside the Modal.", + "slots": "The components used for each slot inside the Modal. Either a string to use a HTML element or a component.", "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details." }, "classDescriptions": { diff --git a/docs/translations/api-docs/multi-select-unstyled/multi-select-unstyled.json b/docs/translations/api-docs/multi-select-unstyled/multi-select-unstyled.json index c671b5deafbf57..03fedd2cb4b5f6 100644 --- a/docs/translations/api-docs/multi-select-unstyled/multi-select-unstyled.json +++ b/docs/translations/api-docs/multi-select-unstyled/multi-select-unstyled.json @@ -3,8 +3,6 @@ "propDescriptions": { "autoFocus": "If true, the select element is focused during the first mount", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the Select. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Input.", "defaultListboxOpen": "If true, the select will be initially open.", "defaultValue": "The default selected values. Use when the component is not controlled.", "disabled": "If true, the select is disabled.", @@ -16,6 +14,8 @@ "onListboxOpenChange": "Callback fired when the component requests to be opened. Use in controlled mode (see listboxOpen).", "optionStringifier": "A function used to convert the option label to a string. It's useful when labels are elements and need to be converted to plain text to enable navigation using character keys on a keyboard.", "renderValue": "Function that customizes the rendering of the selected values.", + "slotProps": "The props used for each slot inside the MultiSelect.", + "slots": "The components used for each slot inside the MultiSelect. Either a string to use a HTML element or a component.", "value": "The selected values. Set to an empty array to deselect all options." }, "classDescriptions": {} diff --git a/docs/translations/api-docs/option-group-unstyled/option-group-unstyled.json b/docs/translations/api-docs/option-group-unstyled/option-group-unstyled.json index f47a92d883f573..9ca7ecf6ce6b64 100644 --- a/docs/translations/api-docs/option-group-unstyled/option-group-unstyled.json +++ b/docs/translations/api-docs/option-group-unstyled/option-group-unstyled.json @@ -2,10 +2,10 @@ "componentDescription": "An unstyled option group to be used within a SelectUnstyled.", "propDescriptions": { "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the OptionGroupUnstyled. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Input.", "disabled": "If true all the options in the group will be disabled.", - "label": "The human-readable description of the group." + "label": "The human-readable description of the group.", + "slotProps": "The props used for each slot inside the Input.", + "slots": "The components used for each slot inside the OptionGroupUnstyled. Either a string to use a HTML element or a component." }, "classDescriptions": {} } diff --git a/docs/translations/api-docs/option-unstyled/option-unstyled.json b/docs/translations/api-docs/option-unstyled/option-unstyled.json index 6ac0517faf17e1..eea211344a1179 100644 --- a/docs/translations/api-docs/option-unstyled/option-unstyled.json +++ b/docs/translations/api-docs/option-unstyled/option-unstyled.json @@ -2,10 +2,10 @@ "componentDescription": "An unstyled option to be used within a SelectUnstyled.", "propDescriptions": { "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the OptionUnstyled. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the OptionUnstyled.", "disabled": "If true, the option will be disabled.", "label": "A text representation of the option's content. Used for keyboard text navigation matching.", + "slotProps": "The props used for each slot inside the OptionUnstyled.", + "slots": "The components used for each slot inside the OptionUnstyled. Either a string to use a HTML element or a component.", "value": "The value of the option." }, "classDescriptions": {} diff --git a/docs/translations/api-docs/popper-unstyled/popper-unstyled.json b/docs/translations/api-docs/popper-unstyled/popper-unstyled.json index e9b7be2b68fbb6..9ee85611896802 100644 --- a/docs/translations/api-docs/popper-unstyled/popper-unstyled.json +++ b/docs/translations/api-docs/popper-unstyled/popper-unstyled.json @@ -3,8 +3,6 @@ "propDescriptions": { "anchorEl": "An HTML element, virtualElement, or a function that returns either. It's used to set the position of the popper. The return value will passed as the reference object of the Popper instance.", "children": "Popper render function or node.", - "components": "The components used for each slot inside the Popper. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Popper.", "container": "An HTML element or function that returns one. The container will have the portal children appended to it.
    By default, it uses the body of the top-level document object, so it's simply document.body most of the time.", "direction": "Direction of the text.", "disablePortal": "The children will be under the DOM hierarchy of the parent component.", @@ -14,6 +12,8 @@ "placement": "Popper placement.", "popperOptions": "Options provided to the Popper.js instance.", "popperRef": "A ref that points to the used popper instance.", + "slotProps": "The props used for each slot inside the Popper.", + "slots": "The components used for each slot inside the Popper. Either a string to use a HTML element or a component.", "transition": "Help supporting a react-transition-group/Transition component." }, "classDescriptions": {} diff --git a/docs/translations/api-docs/popper/popper.json b/docs/translations/api-docs/popper/popper.json index ef073104efbc46..6ffc8353adf6f2 100644 --- a/docs/translations/api-docs/popper/popper.json +++ b/docs/translations/api-docs/popper/popper.json @@ -13,6 +13,8 @@ "placement": "Popper placement.", "popperOptions": "Options provided to the Popper.js instance.", "popperRef": "A ref that points to the used popper instance.", + "slotProps": "The props used for each slot inside the Popper.", + "slots": "The components used for each slot inside the Popper. Either a string to use a HTML element or a component.", "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.", "transition": "Help supporting a react-transition-group/Transition component.", "direction": "Direction of the text." diff --git a/docs/translations/api-docs/select-unstyled/select-unstyled.json b/docs/translations/api-docs/select-unstyled/select-unstyled.json index 715e58f5c0efa1..bf870a481fb773 100644 --- a/docs/translations/api-docs/select-unstyled/select-unstyled.json +++ b/docs/translations/api-docs/select-unstyled/select-unstyled.json @@ -3,8 +3,6 @@ "propDescriptions": { "autoFocus": "If true, the select element is focused during the first mount", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the Select. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Input.", "defaultListboxOpen": "If true, the select will be initially open.", "defaultValue": "The default selected value. Use when the component is not controlled.", "disabled": "If true, the select is disabled.", @@ -16,6 +14,8 @@ "onListboxOpenChange": "Callback fired when the component requests to be opened. Use in controlled mode (see listboxOpen).", "optionStringifier": "A function used to convert the option label to a string. It's useful when labels are elements and need to be converted to plain text to enable navigation using character keys on a keyboard.", "renderValue": "Function that customizes the rendering of the selected value.", + "slotProps": "The props used for each slot inside the Input.", + "slots": "The components used for each slot inside the Select. Either a string to use a HTML element or a component.", "value": "The selected value. Set to null to deselect all options." }, "classDescriptions": {} diff --git a/docs/translations/api-docs/slider-unstyled/slider-unstyled.json b/docs/translations/api-docs/slider-unstyled/slider-unstyled.json index f98df90ecc1ceb..47f3e485a389c4 100644 --- a/docs/translations/api-docs/slider-unstyled/slider-unstyled.json +++ b/docs/translations/api-docs/slider-unstyled/slider-unstyled.json @@ -6,8 +6,6 @@ "aria-valuetext": "A string value that provides a user-friendly name for the current value of the slider.", "classes": "Override or extend the styles applied to the component. See CSS API below for more details.", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the Slider. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Slider.", "defaultValue": "The default value. Use when the component is not controlled.", "disabled": "If true, the component is disabled.", "disableSwap": "If true, the active thumb doesn't swap when moving pointer over a thumb while dragging another thumb.", @@ -22,6 +20,8 @@ "onChangeCommitted": "Callback function that is fired when the mouseup is triggered.

    Signature:
    function(event: React.SyntheticEvent | Event, value: number | Array<number>) => void
    event: The event source of the callback. Warning: This is a generic event not a change event.
    value: The new value.", "orientation": "The component orientation.", "scale": "A transformation function, to change the scale of the slider.", + "slotProps": "The props used for each slot inside the Slider.", + "slots": "The components used for each slot inside the Slider. Either a string to use a HTML element or a component.", "step": "The granularity with which the slider can step through values. (A "discrete" slider.) The min prop serves as the origin for the valid values. We recommend (max - min) to be evenly divisible by the step.
    When step is null, the thumb can only be slid onto marks provided with the marks prop.", "tabIndex": "Tab index attribute of the hidden input element.", "track": "The track presentation:
    - normal the track will render a bar representing the slider value. - inverted the track will render a bar representing the remaining slider value. - false the track will render without a bar.", diff --git a/docs/translations/api-docs/slider/slider.json b/docs/translations/api-docs/slider/slider.json index a97a00a0191ffc..9bab1ec6af7c3e 100644 --- a/docs/translations/api-docs/slider/slider.json +++ b/docs/translations/api-docs/slider/slider.json @@ -7,7 +7,6 @@ "classes": "Override or extend the styles applied to the component. See CSS API below for more details.", "color": "The color of the component. It supports both default and custom theme colors, which can be added as shown in the palette customization guide.", "components": "The components used for each slot inside the Slider. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Slider.", "defaultValue": "The default value. Use when the component is not controlled.", "disabled": "If true, the component is disabled.", "disableSwap": "If true, the active thumb doesn't swap when moving pointer over a thumb while dragging another thumb.", @@ -23,6 +22,8 @@ "orientation": "The component orientation.", "scale": "A transformation function, to change the scale of the slider.", "size": "The size of the slider.", + "slotProps": "The props used for each slot inside the Slider.", + "slots": "The components used for each slot inside the Slider. Either a string to use a HTML element or a component.", "step": "The granularity with which the slider can step through values. (A "discrete" slider.) The min prop serves as the origin for the valid values. We recommend (max - min) to be evenly divisible by the step.
    When step is null, the thumb can only be slid onto marks provided with the marks prop.", "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.", "tabIndex": "Tab index attribute of the hidden input element.", diff --git a/docs/translations/api-docs/snackbar-unstyled/snackbar-unstyled.json b/docs/translations/api-docs/snackbar-unstyled/snackbar-unstyled.json index bc66a2650a8e0b..41e6dce522dfc5 100644 --- a/docs/translations/api-docs/snackbar-unstyled/snackbar-unstyled.json +++ b/docs/translations/api-docs/snackbar-unstyled/snackbar-unstyled.json @@ -3,13 +3,13 @@ "propDescriptions": { "autoHideDuration": "The number of milliseconds to wait before automatically calling the onClose function. onClose should then set the state of the open prop to hide the Snackbar. This behavior is disabled by default with the null value.", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the Snackbar. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Snackbar.", "disableWindowBlurListener": "If true, the autoHideDuration timer will expire even if the window is not focused.", "exited": "The prop used to handle exited transition and unmount the component.", "onClose": "Callback fired when the component requests to be closed. Typically onClose is used to set state in the parent component, which is used to control the Snackbar open prop. The reason parameter can optionally be used to control the response to onClose, for example ignoring clickaway.

    Signature:
    function(event: React.SyntheticEvent<any> | Event, reason: string) => void
    event: The event source of the callback.
    reason: Can be: "timeout" (autoHideDuration expired), "clickaway", or "escapeKeyDown".", "open": "If true, the component is shown.", - "resumeHideDuration": "The number of milliseconds to wait before dismissing after user interaction. If autoHideDuration prop isn't specified, it does nothing. If autoHideDuration prop is specified but resumeHideDuration isn't, we default to autoHideDuration / 2 ms." + "resumeHideDuration": "The number of milliseconds to wait before dismissing after user interaction. If autoHideDuration prop isn't specified, it does nothing. If autoHideDuration prop is specified but resumeHideDuration isn't, we default to autoHideDuration / 2 ms.", + "slotProps": "The props used for each slot inside the Snackbar.", + "slots": "The components used for each slot inside the Snackbar. Either a string to use a HTML element or a component." }, "classDescriptions": {} } diff --git a/docs/translations/api-docs/switch-unstyled/switch-unstyled.json b/docs/translations/api-docs/switch-unstyled/switch-unstyled.json index 2e4d822cf7f90b..804264ceb506e8 100644 --- a/docs/translations/api-docs/switch-unstyled/switch-unstyled.json +++ b/docs/translations/api-docs/switch-unstyled/switch-unstyled.json @@ -3,13 +3,13 @@ "propDescriptions": { "checked": "If true, the component is checked.", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the Switch. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Switch.", "defaultChecked": "The default checked state. Use when the component is not controlled.", "disabled": "If true, the component is disabled.", "onChange": "Callback fired when the state is changed.

    Signature:
    function(event: React.ChangeEvent<HTMLInputElement>) => void
    event: The event source of the callback. You can pull out the new value by accessing event.target.value (string). You can pull out the new checked state by accessing event.target.checked (boolean).", "readOnly": "If true, the component is read only.", - "required": "If true, the input element is required." + "required": "If true, the input element is required.", + "slotProps": "The props used for each slot inside the Switch.", + "slots": "The components used for each slot inside the Switch. Either a string to use a HTML element or a component." }, "classDescriptions": {} } diff --git a/docs/translations/api-docs/tab-panel-unstyled/tab-panel-unstyled.json b/docs/translations/api-docs/tab-panel-unstyled/tab-panel-unstyled.json index 04b5369c4f1f58..dbedd4fcca8487 100644 --- a/docs/translations/api-docs/tab-panel-unstyled/tab-panel-unstyled.json +++ b/docs/translations/api-docs/tab-panel-unstyled/tab-panel-unstyled.json @@ -3,8 +3,8 @@ "propDescriptions": { "children": "The content of the component.", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the TabPanel. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the TabPanel.", + "slotProps": "The props used for each slot inside the TabPanel.", + "slots": "The components used for each slot inside the TabPanel. Either a string to use a HTML element or a component.", "value": "The value of the TabPanel. It will be shown when the Tab with the corresponding value is selected." }, "classDescriptions": {} diff --git a/docs/translations/api-docs/tab-unstyled/tab-unstyled.json b/docs/translations/api-docs/tab-unstyled/tab-unstyled.json index 637d2028bbb5f5..e8fd1c63083a01 100644 --- a/docs/translations/api-docs/tab-unstyled/tab-unstyled.json +++ b/docs/translations/api-docs/tab-unstyled/tab-unstyled.json @@ -3,10 +3,10 @@ "propDescriptions": { "action": "A ref for imperative actions. It currently only supports focusVisible() action.", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the Tab. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Tab.", "disabled": "If true, the component is disabled.", "onChange": "Callback invoked when new value is being set.", + "slotProps": "The props used for each slot inside the Tab.", + "slots": "The components used for each slot inside the Tab. Either a string to use a HTML element or a component.", "value": "You can provide your own value. Otherwise, we fall back to the child position index." }, "classDescriptions": {} diff --git a/docs/translations/api-docs/table-pagination-unstyled/table-pagination-unstyled.json b/docs/translations/api-docs/table-pagination-unstyled/table-pagination-unstyled.json index edab9354721ec1..09a9f234b59f8f 100644 --- a/docs/translations/api-docs/table-pagination-unstyled/table-pagination-unstyled.json +++ b/docs/translations/api-docs/table-pagination-unstyled/table-pagination-unstyled.json @@ -2,8 +2,6 @@ "componentDescription": "A pagination for tables.", "propDescriptions": { "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the TablePagination. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the TablePagination.", "count": "The total number of rows.
    To enable server side pagination for an unknown number of items, provide -1.", "getItemAriaLabel": "Accepts a function which returns a string value that provides a user-friendly name for the current page. This is important for screen reader users.
    For localization purposes, you can use the provided translations.

    Signature:
    function(type: string) => string
    type: The link or button type to format ('first' | 'last' | 'next' | 'previous').", "labelDisplayedRows": "Customize the displayed rows label. Invoked with a { from, to, count, page } object.
    For localization purposes, you can use the provided translations.", @@ -14,7 +12,9 @@ "page": "The zero-based index of the current page.", "rowsPerPage": "The number of rows per page.
    Set -1 to display all the rows.", "rowsPerPageOptions": "Customizes the options of the rows per page select field. If less than two options are available, no select field will be displayed. Use -1 for the value with a custom label to show all the rows.", - "selectId": "Id of the select element within the pagination." + "selectId": "Id of the select element within the pagination.", + "slotProps": "The props used for each slot inside the TablePagination.", + "slots": "The components used for each slot inside the TablePagination. Either a string to use a HTML element or a component." }, "classDescriptions": {} } diff --git a/docs/translations/api-docs/tabs-list-unstyled/tabs-list-unstyled.json b/docs/translations/api-docs/tabs-list-unstyled/tabs-list-unstyled.json index b2578fdfff5408..4cbf9603e0d16f 100644 --- a/docs/translations/api-docs/tabs-list-unstyled/tabs-list-unstyled.json +++ b/docs/translations/api-docs/tabs-list-unstyled/tabs-list-unstyled.json @@ -3,8 +3,8 @@ "propDescriptions": { "children": "The content of the component.", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the TabsList. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the TabsList." + "slotProps": "The props used for each slot inside the TabsList.", + "slots": "The components used for each slot inside the TabsList. Either a string to use a HTML element or a component." }, "classDescriptions": {} } diff --git a/docs/translations/api-docs/tabs-unstyled/tabs-unstyled.json b/docs/translations/api-docs/tabs-unstyled/tabs-unstyled.json index 4df7a7ddb7a28f..b21ea1385dea24 100644 --- a/docs/translations/api-docs/tabs-unstyled/tabs-unstyled.json +++ b/docs/translations/api-docs/tabs-unstyled/tabs-unstyled.json @@ -3,13 +3,13 @@ "propDescriptions": { "children": "The content of the component.", "component": "The component used for the root node. Either a string to use a HTML element or a component.", - "components": "The components used for each slot inside the Tabs. Either a string to use a HTML element or a component.", - "componentsProps": "The props used for each slot inside the Tabs.", "defaultValue": "The default value. Use when the component is not controlled.", "direction": "The direction of the text.", "onChange": "Callback invoked when new value is being set.", "orientation": "The component orientation (layout flow direction).", "selectionFollowsFocus": "If true the selected tab changes on focus. Otherwise it only changes on activation.", + "slotProps": "The props used for each slot inside the Tabs.", + "slots": "The components used for each slot inside the Tabs. Either a string to use a HTML element or a component.", "value": "The value of the currently selected Tab. If you don't want any selected Tab, you can set this prop to false." }, "classDescriptions": {} diff --git a/examples/mui-base-with-tailwind-css/src/Button.tsx b/examples/mui-base-with-tailwind-css/src/Button.tsx index 81392aef4fbe49..8f09e51070f7a0 100644 --- a/examples/mui-base-with-tailwind-css/src/Button.tsx +++ b/examples/mui-base-with-tailwind-css/src/Button.tsx @@ -11,7 +11,7 @@ const Button = React.forwardRef(function Button( return ( ({ className: `hover:text-cyan-500 transition-colors ${ state.focusVisible ? 'outline-0 ring-2 ring-cyan-500' : '' diff --git a/examples/mui-base-with-tailwind-css/src/Slider.tsx b/examples/mui-base-with-tailwind-css/src/Slider.tsx index f4ade15f847bce..61f32daad3f92f 100644 --- a/examples/mui-base-with-tailwind-css/src/Slider.tsx +++ b/examples/mui-base-with-tailwind-css/src/Slider.tsx @@ -29,10 +29,10 @@ const Slider = React.forwardRef(function Slider( diff --git a/packages/mui-base/src/BadgeUnstyled/BadgeUnstyled.spec.tsx b/packages/mui-base/src/BadgeUnstyled/BadgeUnstyled.spec.tsx index 84b5707b1fa890..c4aa4d46ef96cc 100644 --- a/packages/mui-base/src/BadgeUnstyled/BadgeUnstyled.spec.tsx +++ b/packages/mui-base/src/BadgeUnstyled/BadgeUnstyled.spec.tsx @@ -21,7 +21,7 @@ const Badge = React.forwardRef(function Badge( return ; }); -const styledBadge = ; +const styledBadge = ; const polymorphicComponentTest = () => { const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> = () =>
    ; diff --git a/packages/mui-base/src/BadgeUnstyled/BadgeUnstyled.tsx b/packages/mui-base/src/BadgeUnstyled/BadgeUnstyled.tsx index e5d23bbed64cbc..85d351c7af3fa0 100644 --- a/packages/mui-base/src/BadgeUnstyled/BadgeUnstyled.tsx +++ b/packages/mui-base/src/BadgeUnstyled/BadgeUnstyled.tsx @@ -38,10 +38,10 @@ const BadgeUnstyled = React.forwardRef(function BadgeUnstyled(props: BadgeUnstyl badgeContent: badgeContentProp, component, children, - components = {}, - componentsProps = {}, invisible: invisibleProp, max: maxProp = 99, + slotProps = {}, + slots = {}, showZero = false, ...other } = props; @@ -61,10 +61,10 @@ const BadgeUnstyled = React.forwardRef(function BadgeUnstyled(props: BadgeUnstyl const classes = useUtilityClasses(ownerState); - const Root = component || components.Root || 'span'; + const Root = component || slots.root || 'span'; const rootProps: WithOptionalOwnerState = useSlotProps({ elementType: Root, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, additionalProps: { ref, @@ -73,10 +73,10 @@ const BadgeUnstyled = React.forwardRef(function BadgeUnstyled(props: BadgeUnstyl className: classes.root, }); - const Badge = components.Badge || 'span'; + const Badge = slots.badge || 'span'; const badgeProps: WithOptionalOwnerState = useSlotProps({ elementType: Badge, - externalSlotProps: componentsProps.badge, + externalSlotProps: slotProps.badge, ownerState, className: classes.badge, }); @@ -107,23 +107,6 @@ BadgeUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the Badge. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Badge: PropTypes.elementType, - Root: PropTypes.elementType, - }), - /** - * The props used for each slot inside the Badge. - * @default {} - */ - componentsProps: PropTypes.shape({ - badge: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * If `true`, the badge is invisible. * @default false @@ -139,6 +122,23 @@ BadgeUnstyled.propTypes /* remove-proptypes */ = { * @default false */ showZero: PropTypes.bool, + /** + * The props used for each slot inside the Badge. + * @default {} + */ + slotProps: PropTypes.shape({ + badge: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the Badge. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + badge: PropTypes.elementType, + root: PropTypes.elementType, + }), } as any; export default BadgeUnstyled; diff --git a/packages/mui-base/src/BadgeUnstyled/BadgeUnstyled.types.ts b/packages/mui-base/src/BadgeUnstyled/BadgeUnstyled.types.ts index 7da158439ff578..4f678167153bdf 100644 --- a/packages/mui-base/src/BadgeUnstyled/BadgeUnstyled.types.ts +++ b/packages/mui-base/src/BadgeUnstyled/BadgeUnstyled.types.ts @@ -13,19 +13,28 @@ export type BadgeUnstyledOwnerState = BadgeUnstyledProps & { export interface BadgeUnstyledOwnProps { /** - * The components used for each slot inside the Badge. - * Either a string to use a HTML element or a component. - * @default {} + * The content rendered within the badge. */ - components?: { - Root?: React.ElementType; - Badge?: React.ElementType; - }; + badgeContent?: React.ReactNode; + /** + * The badge will be added relative to this node. + */ + children?: React.ReactNode; + /** + * If `true`, the badge is invisible. + * @default false + */ + invisible?: boolean; + /** + * Max count to show. + * @default 99 + */ + max?: number; /** * The props used for each slot inside the Badge. * @default {} */ - componentsProps?: { + slotProps?: { root?: SlotComponentProps< 'span', BadgeUnstyledComponentsPropsOverrides, @@ -38,23 +47,14 @@ export interface BadgeUnstyledOwnProps { >; }; /** - * The content rendered within the badge. - */ - badgeContent?: React.ReactNode; - /** - * The badge will be added relative to this node. - */ - children?: React.ReactNode; - /** - * If `true`, the badge is invisible. - * @default false - */ - invisible?: boolean; - /** - * Max count to show. - * @default 99 + * The components used for each slot inside the Badge. + * Either a string to use a HTML element or a component. + * @default {} */ - max?: number; + slots?: { + root?: React.ElementType; + badge?: React.ElementType; + }; /** * Controls whether the badge is hidden when `badgeContent` is zero. * @default false diff --git a/packages/mui-base/src/ButtonUnstyled/ButtonUnstyled.spec.tsx b/packages/mui-base/src/ButtonUnstyled/ButtonUnstyled.spec.tsx index 96d0a01eaa489d..9601799489cd9f 100644 --- a/packages/mui-base/src/ButtonUnstyled/ButtonUnstyled.spec.tsx +++ b/packages/mui-base/src/ButtonUnstyled/ButtonUnstyled.spec.tsx @@ -20,7 +20,7 @@ const CustomButtonRoot = React.forwardRef(function CustomButtonRoot( }); function ButtonWithCustomRoot(props: ButtonUnstyledProps) { - return ; + return ; } const polymorphicComponentTest = () => { diff --git a/packages/mui-base/src/ButtonUnstyled/ButtonUnstyled.tsx b/packages/mui-base/src/ButtonUnstyled/ButtonUnstyled.tsx index 2de25894ed04e3..502a2a493c9383 100644 --- a/packages/mui-base/src/ButtonUnstyled/ButtonUnstyled.tsx +++ b/packages/mui-base/src/ButtonUnstyled/ButtonUnstyled.tsx @@ -45,8 +45,6 @@ const ButtonUnstyled = React.forwardRef(function ButtonUnstyled< action, children, component, - components = {}, - componentsProps = {}, disabled, focusableWhenDisabled = false, onBlur, @@ -56,6 +54,8 @@ const ButtonUnstyled = React.forwardRef(function ButtonUnstyled< onKeyDown, onKeyUp, onMouseLeave, + slotProps = {}, + slots = {}, ...other } = props; @@ -86,12 +86,12 @@ const ButtonUnstyled = React.forwardRef(function ButtonUnstyled< const classes = useUtilityClasses(ownerState); - const Root: React.ElementType = component ?? components.Root ?? 'button'; + const Root: React.ElementType = component ?? slots.root ?? 'button'; const rootProps: WithOptionalOwnerState = useSlotProps({ elementType: Root, getSlotProps: getRootProps, externalForwardedProps: other, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, additionalProps: { ref: forwardedRef, }, @@ -127,21 +127,6 @@ ButtonUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the Button. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Root: PropTypes.elementType, - }), - /** - * The props used for each slot inside the Button. - * @default {} - */ - componentsProps: PropTypes.shape({ - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * If `true`, the component is disabled. * @default false @@ -180,6 +165,21 @@ ButtonUnstyled.propTypes /* remove-proptypes */ = { * @ignore */ onMouseLeave: PropTypes.func, + /** + * The props used for each slot inside the Button. + * @default {} + */ + slotProps: PropTypes.shape({ + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the Button. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + root: PropTypes.elementType, + }), } as any; export default ButtonUnstyled; diff --git a/packages/mui-base/src/ButtonUnstyled/ButtonUnstyled.types.ts b/packages/mui-base/src/ButtonUnstyled/ButtonUnstyled.types.ts index fecd4a0a92644c..0a77cb87f78d26 100644 --- a/packages/mui-base/src/ButtonUnstyled/ButtonUnstyled.types.ts +++ b/packages/mui-base/src/ButtonUnstyled/ButtonUnstyled.types.ts @@ -16,25 +16,25 @@ export interface ButtonUnstyledOwnProps extends Omit action?: React.Ref; children?: React.ReactNode; className?: string; - /** - * The components used for each slot inside the Button. - * Either a string to use a HTML element or a component. - * @default {} - */ - components?: { - Root?: React.ElementType; - }; /** * The props used for each slot inside the Button. * @default {} */ - componentsProps?: { + slotProps?: { root?: SlotComponentProps< 'button', ButtonUnstyledComponentsPropsOverrides, ButtonUnstyledOwnerState >; }; + /** + * The components used for each slot inside the Button. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots?: { + root?: React.ElementType; + }; } export type ButtonUnstyledProps< diff --git a/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.spec.tsx b/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.spec.tsx index a029a461ebac01..f2326aee4cf0b7 100644 --- a/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.spec.tsx +++ b/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.spec.tsx @@ -44,4 +44,4 @@ function Root(props: FormControlUnstyledRootSlotProps) { ); } -const StyledFormControl = ; +const StyledFormControl = ; diff --git a/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.tsx b/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.tsx index 2901488f896a29..a905ae08a1991c 100644 --- a/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.tsx +++ b/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.tsx @@ -75,12 +75,12 @@ const FormControlUnstyled = React.forwardRef(function FormControlUnstyled< defaultValue, children, component, - components = {}, - componentsProps = {}, disabled = false, error = false, onChange, required = false, + slotProps = {}, + slots = {}, value: incomingValue, ...other } = props; @@ -139,10 +139,10 @@ const FormControlUnstyled = React.forwardRef(function FormControlUnstyled< return children; }; - const Root = component ?? components.Root ?? 'div'; + const Root = component ?? slots.root ?? 'div'; const rootProps: WithOptionalOwnerState = useSlotProps({ elementType: Root, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, additionalProps: { ref, @@ -176,20 +176,6 @@ FormControlUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the FormControl. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Root: PropTypes.elementType, - }), - /** - * @ignore - */ - componentsProps: PropTypes.shape({ - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * @ignore */ @@ -213,6 +199,21 @@ FormControlUnstyled.propTypes /* remove-proptypes */ = { * @default false */ required: PropTypes.bool, + /** + * The props used for each slot inside the FormControl. + * @default {} + */ + slotProps: PropTypes.shape({ + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the FormControl. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + root: PropTypes.elementType, + }), /** * @ignore */ diff --git a/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.types.ts b/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.types.ts index 8e1db0bbb3e251..02f0fbd03105e1 100644 --- a/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.types.ts +++ b/packages/mui-base/src/FormControlUnstyled/FormControlUnstyled.types.ts @@ -15,21 +15,6 @@ export interface FormControlUnstyledOwnProps { * Class name applied to the root element. */ className?: string; - /** - * The components used for each slot inside the FormControl. - * Either a string to use a HTML element or a component. - * @default {} - */ - components?: { - Root?: React.ElementType; - }; - componentsProps?: { - root?: SlotComponentProps< - 'div', - FormControlUnstyledComponentsPropsOverrides, - FormControlUnstyledOwnerState - >; - }; defaultValue?: unknown; /** * If `true`, the label, input and helper text should be displayed in a disabled state. @@ -47,6 +32,25 @@ export interface FormControlUnstyledOwnProps { * @default false */ required?: boolean; + /** + * The props used for each slot inside the FormControl. + * @default {} + */ + slotProps?: { + root?: SlotComponentProps< + 'div', + FormControlUnstyledComponentsPropsOverrides, + FormControlUnstyledOwnerState + >; + }; + /** + * The components used for each slot inside the FormControl. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots?: { + root?: React.ElementType; + }; value?: unknown; } diff --git a/packages/mui-base/src/InputUnstyled/InputUnstyled.spec.tsx b/packages/mui-base/src/InputUnstyled/InputUnstyled.spec.tsx index 6328d323a2dc68..a056432b43100b 100644 --- a/packages/mui-base/src/InputUnstyled/InputUnstyled.spec.tsx +++ b/packages/mui-base/src/InputUnstyled/InputUnstyled.spec.tsx @@ -21,7 +21,7 @@ const InputInput = React.forwardRef(function InputInput( return ; }); -const styledInput = ; +const styledInput = ; const polymorphicComponentTest = () => { const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> = () =>
    ; diff --git a/packages/mui-base/src/InputUnstyled/InputUnstyled.test.tsx b/packages/mui-base/src/InputUnstyled/InputUnstyled.test.tsx index 85cb67679a25b1..461830f23d64b1 100644 --- a/packages/mui-base/src/InputUnstyled/InputUnstyled.test.tsx +++ b/packages/mui-base/src/InputUnstyled/InputUnstyled.test.tsx @@ -53,12 +53,7 @@ describe('', () => { ); render( - , + , ); }); }); diff --git a/packages/mui-base/src/InputUnstyled/InputUnstyled.tsx b/packages/mui-base/src/InputUnstyled/InputUnstyled.tsx index 9daba9ae64b221..b3f27987b0e74c 100644 --- a/packages/mui-base/src/InputUnstyled/InputUnstyled.tsx +++ b/packages/mui-base/src/InputUnstyled/InputUnstyled.tsx @@ -35,8 +35,6 @@ const InputUnstyled = React.forwardRef(function InputUnstyled( autoFocus, className, component, - components = {}, - componentsProps = {}, defaultValue, disabled, endAdornment, @@ -57,6 +55,8 @@ const InputUnstyled = React.forwardRef(function InputUnstyled( value, type: typeProp, rows, + slotProps = {}, + slots = {}, minRows, maxRows, ...other @@ -123,11 +123,11 @@ const InputUnstyled = React.forwardRef(function InputUnstyled( type, }; - const Root = component ?? components.Root ?? 'div'; + const Root = component ?? slots.root ?? 'div'; const rootProps: WithOptionalOwnerState = useSlotProps({ elementType: Root, getSlotProps: getRootProps, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, additionalProps: { ref: forwardedRef, @@ -136,12 +136,12 @@ const InputUnstyled = React.forwardRef(function InputUnstyled( className: [classes.root, rootStateClasses, className], }); - const Input = multiline ? components.Textarea ?? 'textarea' : components.Input ?? 'input'; + const Input = multiline ? slots.textarea ?? 'textarea' : slots.input ?? 'input'; const inputProps: WithOptionalOwnerState = useSlotProps({ elementType: Input, getSlotProps: (otherHandlers: EventHandlers) => getInputProps({ ...otherHandlers, ...propsToForward }), - externalSlotProps: componentsProps.input, + externalSlotProps: slotProps.input, additionalProps: { rows: multiline ? rows : undefined, ...(multiline && @@ -215,24 +215,6 @@ InputUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the InputBase. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Input: PropTypes.elementType, - Root: PropTypes.elementType, - Textarea: PropTypes.elementType, - }), - /** - * The props used for each slot inside the Input. - * @default {} - */ - componentsProps: PropTypes.shape({ - input: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * The default value. Use when the component is not controlled. */ @@ -314,6 +296,24 @@ InputUnstyled.propTypes /* remove-proptypes */ = { * Number of rows to display when multiline option is set to true. */ rows: PropTypes.number, + /** + * The props used for each slot inside the Input. + * @default {} + */ + slotProps: PropTypes.shape({ + input: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the InputBase. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + input: PropTypes.elementType, + root: PropTypes.elementType, + textarea: PropTypes.elementType, + }), /** * Leading adornment for this input. */ diff --git a/packages/mui-base/src/InputUnstyled/InputUnstyled.types.ts b/packages/mui-base/src/InputUnstyled/InputUnstyled.types.ts index 0eb1d3089c7ff8..a9e20922507b37 100644 --- a/packages/mui-base/src/InputUnstyled/InputUnstyled.types.ts +++ b/packages/mui-base/src/InputUnstyled/InputUnstyled.types.ts @@ -75,32 +75,6 @@ export type InputUnstyledOwnProps = (SingleLineInputUnstyledProps | MultiLineInp * Class name applied to the root element. */ className?: string; - /** - * The components used for each slot inside the InputBase. - * Either a string to use a HTML element or a component. - * @default {} - */ - components?: { - Root?: React.ElementType; - Input?: React.ElementType; - Textarea?: React.ElementType; - }; - /** - * The props used for each slot inside the Input. - * @default {} - */ - componentsProps?: { - root?: SlotComponentProps< - 'div', - InputUnstyledComponentsPropsOverrides, - InputUnstyledOwnerState - >; - input?: SlotComponentProps< - 'input', - InputUnstyledComponentsPropsOverrides, - InputUnstyledOwnerState - >; - }; /** * Trailing adornment for this input. */ @@ -124,6 +98,32 @@ export type InputUnstyledOwnProps = (SingleLineInputUnstyledProps | MultiLineInp * (not from interacting with the field). */ readOnly?: boolean; + /** + * The props used for each slot inside the Input. + * @default {} + */ + slotProps?: { + root?: SlotComponentProps< + 'div', + InputUnstyledComponentsPropsOverrides, + InputUnstyledOwnerState + >; + input?: SlotComponentProps< + 'input', + InputUnstyledComponentsPropsOverrides, + InputUnstyledOwnerState + >; + }; + /** + * The components used for each slot inside the InputBase. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots?: { + root?: React.ElementType; + input?: React.ElementType; + textarea?: React.ElementType; + }; /** * Leading adornment for this input. */ @@ -147,7 +147,7 @@ export type InputUnstyledProps< }; export type InputUnstyledOwnerState = Simplify< - Omit & { + Omit & { formControlContext: FormControlUnstyledState | undefined; focused: boolean; type: React.InputHTMLAttributes['type'] | undefined; diff --git a/packages/mui-base/src/InputUnstyled/useInput.ts b/packages/mui-base/src/InputUnstyled/useInput.ts index 2e65e79aefa51c..0d67f1df94143b 100644 --- a/packages/mui-base/src/InputUnstyled/useInput.ts +++ b/packages/mui-base/src/InputUnstyled/useInput.ts @@ -66,7 +66,7 @@ export default function useInput(parameters: UseInputParameters) { if (instance && instance.nodeName !== 'INPUT' && !instance.focus) { console.error( [ - 'MUI: You have provided a `components.Input` to the input component', + 'MUI: You have provided a `slots.input` to the input component', 'that does not correctly handle the `ref` prop.', 'Make sure the `ref` prop is called with a HTMLInputElement.', ].join('\n'), @@ -130,7 +130,7 @@ export default function useInput(parameters: UseInputParameters) { if (element == null) { throw new MuiError( 'MUI: Expected valid input target. ' + - 'Did you use a custom `components.Input` and forget to forward refs? ' + + 'Did you use a custom `slots.input` and forget to forward refs? ' + 'See https://mui.com/r/input-component-ref-interface for more info.', ); } diff --git a/packages/mui-base/src/MenuItemUnstyled/MenuItemUnstyled.tsx b/packages/mui-base/src/MenuItemUnstyled/MenuItemUnstyled.tsx index 39b2d00d853268..704b91f37fb501 100644 --- a/packages/mui-base/src/MenuItemUnstyled/MenuItemUnstyled.tsx +++ b/packages/mui-base/src/MenuItemUnstyled/MenuItemUnstyled.tsx @@ -38,9 +38,9 @@ const MenuItemUnstyled = React.forwardRef(function MenuItemUnstyled< children, disabled: disabledProp = false, component, - components = {}, - componentsProps = {}, label, + slotProps = {}, + slots = {}, ...other } = props; @@ -54,11 +54,11 @@ const MenuItemUnstyled = React.forwardRef(function MenuItemUnstyled< const classes = getUtilityClasses(ownerState); - const Root = component ?? components.Root ?? 'li'; + const Root = component ?? slots.root ?? 'li'; const rootProps = useSlotProps({ elementType: Root, getSlotProps: getRootProps, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, className: classes.root, ownerState, @@ -81,21 +81,6 @@ MenuItemUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the MenuItem. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Root: PropTypes.elementType, - }), - /** - * The props used for each slot inside the MenuItem. - * @default {} - */ - componentsProps: PropTypes.shape({ - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * If `true`, the menu item will be disabled. * @default false @@ -106,6 +91,21 @@ MenuItemUnstyled.propTypes /* remove-proptypes */ = { * Used for keyboard text navigation matching. */ label: PropTypes.string, + /** + * The props used for each slot inside the MenuItem. + * @default {} + */ + slotProps: PropTypes.shape({ + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the MenuItem. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + root: PropTypes.elementType, + }), } as any; export default MenuItemUnstyled; diff --git a/packages/mui-base/src/MenuItemUnstyled/MenuItemUnstyled.types.ts b/packages/mui-base/src/MenuItemUnstyled/MenuItemUnstyled.types.ts index 9c9e7bb1629ffa..4d564c2ee4585b 100644 --- a/packages/mui-base/src/MenuItemUnstyled/MenuItemUnstyled.types.ts +++ b/packages/mui-base/src/MenuItemUnstyled/MenuItemUnstyled.types.ts @@ -23,14 +23,14 @@ export interface MenuItemUnstyledOwnProps { * Either a string to use a HTML element or a component. * @default {} */ - components?: { - Root?: React.ElementType; + slots?: { + root?: React.ElementType; }; /** * The props used for each slot inside the MenuItem. * @default {} */ - componentsProps?: { + slotProps?: { root?: SlotComponentProps< 'li', MenuItemUnstyledComponentsPropsOverrides, diff --git a/packages/mui-base/src/MenuUnstyled/MenuUnstyled.test.tsx b/packages/mui-base/src/MenuUnstyled/MenuUnstyled.test.tsx index 60408943f15377..2507e801cc2ceb 100644 --- a/packages/mui-base/src/MenuUnstyled/MenuUnstyled.test.tsx +++ b/packages/mui-base/src/MenuUnstyled/MenuUnstyled.test.tsx @@ -34,7 +34,7 @@ describe('MenuUnstyled', () => { expectedClassName: menuUnstyledClasses.listbox, }, }, - skip: ['reactTestRenderer', 'propsSpread', 'componentProp', 'componentsProp'], + skip: ['reactTestRenderer', 'propsSpread', 'componentProp', 'slotsProp'], })); describe('keyboard navigation', () => { diff --git a/packages/mui-base/src/MenuUnstyled/MenuUnstyled.tsx b/packages/mui-base/src/MenuUnstyled/MenuUnstyled.tsx index f6d0482562a056..1abbc8d0460e2e 100644 --- a/packages/mui-base/src/MenuUnstyled/MenuUnstyled.tsx +++ b/packages/mui-base/src/MenuUnstyled/MenuUnstyled.tsx @@ -42,12 +42,12 @@ const MenuUnstyled = React.forwardRef(function MenuUnstyled< anchorEl, children, component, - components = {}, - componentsProps = {}, keepMounted = false, listboxId, onClose, open = false, + slotProps = {}, + slots = {}, ...other } = props; @@ -81,11 +81,11 @@ const MenuUnstyled = React.forwardRef(function MenuUnstyled< const classes = getUtilityClasses(ownerState); - const Root = component ?? components.Root ?? PopperUnstyled; + const Root = component ?? slots.root ?? PopperUnstyled; const rootProps: MenuUnstyledRootSlotProps = useSlotProps({ elementType: Root, externalForwardedProps: other, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, additionalProps: { anchorEl, open, @@ -97,11 +97,11 @@ const MenuUnstyled = React.forwardRef(function MenuUnstyled< ownerState, }) as MenuUnstyledRootSlotProps; - const Listbox = components.Listbox ?? 'ul'; + const Listbox = slots.listbox ?? 'ul'; const listboxProps = useSlotProps({ elementType: Listbox, getSlotProps: getListboxProps, - externalSlotProps: componentsProps.listbox, + externalSlotProps: slotProps.listbox, ownerState, className: classes.listbox, }); @@ -152,23 +152,6 @@ MenuUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the Menu. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Listbox: PropTypes.elementType, - Root: PropTypes.elementType, - }), - /** - * The props used for each slot inside the Menu. - * @default {} - */ - componentsProps: PropTypes.shape({ - listbox: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * Always keep the menu in the DOM. * This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Menu. @@ -189,6 +172,23 @@ MenuUnstyled.propTypes /* remove-proptypes */ = { * @default false */ open: PropTypes.bool, + /** + * The props used for each slot inside the Menu. + * @default {} + */ + slotProps: PropTypes.shape({ + listbox: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the Menu. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + listbox: PropTypes.elementType, + root: PropTypes.elementType, + }), } as any; export default MenuUnstyled; diff --git a/packages/mui-base/src/MenuUnstyled/MenuUnstyled.types.ts b/packages/mui-base/src/MenuUnstyled/MenuUnstyled.types.ts index 904088d1cdb16d..df7bc8df461c9c 100644 --- a/packages/mui-base/src/MenuUnstyled/MenuUnstyled.types.ts +++ b/packages/mui-base/src/MenuUnstyled/MenuUnstyled.types.ts @@ -26,19 +26,27 @@ export interface MenuUnstyledOwnProps { children?: React.ReactNode; className?: string; /** - * The components used for each slot inside the Menu. - * Either a string to use a HTML element or a component. - * @default {} + * Always keep the menu in the DOM. + * This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Menu. + * + * @default false */ - components?: { - Root?: React.ElementType; - Listbox?: React.ElementType; - }; + keepMounted?: boolean; + listboxId?: string; + /** + * Triggered when focus leaves the menu and the menu should close. + */ + onClose?: () => void; + /** + * Controls whether the menu is displayed. + * @default false + */ + open?: boolean; /** * The props used for each slot inside the Menu. * @default {} */ - componentsProps?: { + slotProps?: { root?: SlotComponentProps< typeof PopperUnstyled, MenuUnstyledComponentsPropsOverrides, @@ -51,22 +59,14 @@ export interface MenuUnstyledOwnProps { >; }; /** - * Always keep the menu in the DOM. - * This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Menu. - * - * @default false - */ - keepMounted?: boolean; - listboxId?: string; - /** - * Triggered when focus leaves the menu and the menu should close. - */ - onClose?: () => void; - /** - * Controls whether the menu is displayed. - * @default false + * The components used for each slot inside the Menu. + * Either a string to use a HTML element or a component. + * @default {} */ - open?: boolean; + slots?: { + root?: React.ElementType; + listbox?: React.ElementType; + }; } export interface MenuUnstyledTypeMap

    { diff --git a/packages/mui-base/src/ModalUnstyled/ModalUnstyled.js b/packages/mui-base/src/ModalUnstyled/ModalUnstyled.js index 4dc372b67dcc1d..aaacb78f92f96c 100644 --- a/packages/mui-base/src/ModalUnstyled/ModalUnstyled.js +++ b/packages/mui-base/src/ModalUnstyled/ModalUnstyled.js @@ -56,8 +56,6 @@ const ModalUnstyled = React.forwardRef(function ModalUnstyled(props, ref) { classes: classesProp, closeAfterTransition = false, component = 'div', - components = {}, - componentsProps = {}, container, disableAutoFocus = false, disableEnforceFocus = false, @@ -77,6 +75,8 @@ const ModalUnstyled = React.forwardRef(function ModalUnstyled(props, ref) { /* eslint-disable react/prop-types */ onTransitionEnter, onTransitionExited, + slotProps = {}, + slots = {}, ...other } = props; @@ -235,10 +235,10 @@ const ModalUnstyled = React.forwardRef(function ModalUnstyled(props, ref) { childProps.onExited = createChainedFunction(handleExited, children.props.onExited); } - const Root = components.Root || component; + const Root = slots.root || component; const rootProps = useSlotProps({ elementType: Root, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, additionalProps: { ref: handleRef, @@ -249,15 +249,16 @@ const ModalUnstyled = React.forwardRef(function ModalUnstyled(props, ref) { ownerState, }); - const BackdropComponent = components.Backdrop; + const BackdropComponent = slots.backdrop; const backdropProps = useSlotProps({ elementType: BackdropComponent, - externalSlotProps: componentsProps.backdrop, + externalSlotProps: slotProps.backdrop, additionalProps: { 'aria-hidden': true, onClick: handleBackdropClick, open, }, + className: classes.backdrop, ownerState, }); @@ -312,23 +313,6 @@ ModalUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the Modal. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Backdrop: PropTypes.elementType, - Root: PropTypes.elementType, - }), - /** - * The props used for each slot inside the Modal. - * @default {} - */ - componentsProps: PropTypes.shape({ - backdrop: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * An HTML element or function that returns one. * The `container` will have the portal children appended to it. @@ -412,6 +396,23 @@ ModalUnstyled.propTypes /* remove-proptypes */ = { * If `true`, the component is shown. */ open: PropTypes.bool.isRequired, + /** + * The props used for each slot inside the Modal. + * @default {} + */ + slotProps: PropTypes.shape({ + backdrop: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the Modal. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + backdrop: PropTypes.elementType, + root: PropTypes.elementType, + }), }; export default ModalUnstyled; diff --git a/packages/mui-base/src/ModalUnstyled/ModalUnstyled.spec.tsx b/packages/mui-base/src/ModalUnstyled/ModalUnstyled.spec.tsx index abf5aed5cce8e9..d0ee09d2efa2e2 100644 --- a/packages/mui-base/src/ModalUnstyled/ModalUnstyled.spec.tsx +++ b/packages/mui-base/src/ModalUnstyled/ModalUnstyled.spec.tsx @@ -16,7 +16,7 @@ function Backdrop(props: ModalUnstyledBackdropSlotProps) { } const styledModal = ( - +

    ); diff --git a/packages/mui-base/src/ModalUnstyled/ModalUnstyled.test.js b/packages/mui-base/src/ModalUnstyled/ModalUnstyled.test.js index 0ac24e2c9f99c0..0d808c50f35031 100644 --- a/packages/mui-base/src/ModalUnstyled/ModalUnstyled.test.js +++ b/packages/mui-base/src/ModalUnstyled/ModalUnstyled.test.js @@ -1,9 +1,10 @@ import * as React from 'react'; import { expect } from 'chai'; -import { createRenderer, describeConformance } from 'test/utils'; +import { createMount, createRenderer, describeConformanceUnstyled } from 'test/utils'; import ModalUnstyled, { modalUnstyledClasses as classes } from '@mui/base/ModalUnstyled'; describe('', () => { + const mount = createMount(); const { render } = createRenderer(); let savedBodyStyle; @@ -15,7 +16,7 @@ describe('', () => { document.body.setAttribute('style', savedBodyStyle); }); - describeConformance( + describeConformanceUnstyled(
    , @@ -23,12 +24,17 @@ describe('', () => { classes, inheritComponent: 'div', render, + mount, refInstanceof: window.HTMLDivElement, + slots: { + root: { + expectedClassName: classes.root, + testWithElement: null, + }, + }, skip: [ - 'rootClass', // portal, can't determin the root - 'themeDefaultProps', // unstyled - 'themeStyleOverrides', // unstyled - 'themeVariants', // unstyled + 'propsSpread', + 'slotsProp', 'reactTestRenderer', // portal https://github.com/facebook/react/issues/11565 ], }), @@ -47,7 +53,7 @@ describe('', () => { ); render( - +
    , ); @@ -61,8 +67,8 @@ describe('', () => { render( diff --git a/packages/mui-base/src/ModalUnstyled/ModalUnstyled.types.ts b/packages/mui-base/src/ModalUnstyled/ModalUnstyled.types.ts index 6580304a3c571d..079ad5241e41ea 100644 --- a/packages/mui-base/src/ModalUnstyled/ModalUnstyled.types.ts +++ b/packages/mui-base/src/ModalUnstyled/ModalUnstyled.types.ts @@ -20,31 +20,6 @@ export interface ModalUnstyledOwnProps { * @default false */ closeAfterTransition?: boolean; - /** - * The components used for each slot inside the Modal. - * Either a string to use a HTML element or a component. - * @default {} - */ - components?: { - Root?: React.ElementType; - Backdrop?: React.ElementType; - }; - /** - * The props used for each slot inside the Modal. - * @default {} - */ - componentsProps?: { - root?: SlotComponentProps< - 'div', - ModalUnstyledComponentsPropsOverrides, - ModalUnstyledOwnerState - >; - backdrop?: SlotComponentProps< - 'div', - ModalUnstyledComponentsPropsOverrides, - ModalUnstyledOwnerState - >; - }; /** * An HTML element or function that returns one. * The `container` will have the portal children appended to it. @@ -123,6 +98,31 @@ export interface ModalUnstyledOwnProps { * If `true`, the component is shown. */ open: boolean; + /** + * The props used for each slot inside the Modal. + * @default {} + */ + slotProps?: { + root?: SlotComponentProps< + 'div', + ModalUnstyledComponentsPropsOverrides, + ModalUnstyledOwnerState + >; + backdrop?: SlotComponentProps< + 'div', + ModalUnstyledComponentsPropsOverrides, + ModalUnstyledOwnerState + >; + }; + /** + * The components used for each slot inside the Modal. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots?: { + root?: React.ElementType; + backdrop?: React.ElementType; + }; } export interface ModalUnstyledTypeMap

    { diff --git a/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.spec.tsx b/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.spec.tsx index 93795851b2382d..c4737b70af4b87 100644 --- a/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.spec.tsx +++ b/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.spec.tsx @@ -9,7 +9,7 @@ import { const MultiSelectUnstyledComponentsPropsOverridesTest = ( (props: MultiSelectUnstyledPopperSlotPro const MultiSelectUnstyledRootComponentOverridesTest = ( ); const MultiSelectUnstyledPopperComponentOverridesTest = ( ); @@ -61,18 +61,18 @@ function InvalidPopper({ requiredProp }: { requiredProp: string }) { const MultiSelectUnstyledComponentsOverridesUsingInvalidComponentTest = ( ); const MultiSelectUnstyledComponentsOverridesUsingHostComponentTest = ( ); diff --git a/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.test.tsx b/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.test.tsx index f6b57f21eef9aa..0efd2271ef89dd 100644 --- a/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.test.tsx +++ b/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.test.tsx @@ -52,7 +52,7 @@ describe('MultiSelectUnstyled', () => { ['Enter', 'ArrowDown', 'ArrowUp'].forEach((key) => { it(`opens the dropdown when the "${key}" key is down on the button`, () => { // can't use the default native `button` as it doesn't treat enter or space press as a click - const { getByRole } = render(); + const { getByRole } = render(); const button = getByRole('button'); act(() => { button.focus(); @@ -67,7 +67,7 @@ describe('MultiSelectUnstyled', () => { it(`opens the dropdown when the " " key is let go on the button`, () => { // can't use the default native `button` as it doesn't treat enter or space press as a click - const { getByRole } = render(); + const { getByRole } = render(); const button = getByRole('button'); act(() => { button.focus(); @@ -326,7 +326,7 @@ describe('MultiSelectUnstyled', () => { setValue(v)} - componentsProps={{ + slotProps={{ root: { 'data-testid': 'select', } as any, diff --git a/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.tsx b/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.tsx index cd64aa87090cbe..8b669dfda2a197 100644 --- a/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.tsx +++ b/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.tsx @@ -83,8 +83,6 @@ const MultiSelectUnstyled = React.forwardRef(function MultiSelectUnstyled(null); const listboxRef = React.useRef(null); - const Button = component ?? components.Root ?? 'button'; - const ListboxRoot = components.Listbox ?? 'ul'; - const Popper = components.Popper ?? PopperUnstyled; + const Button = component ?? slots.root ?? 'button'; + const ListboxRoot = slots.listbox ?? 'ul'; + const Popper = slots.popper ?? PopperUnstyled; const handleButtonRefChange = React.useCallback((element: HTMLElement | null) => { setButtonDefined(element != null); @@ -187,7 +187,7 @@ const MultiSelectUnstyled = React.forwardRef(function MultiSelectUnstyled = useSlotProps({ elementType: Popper, - externalSlotProps: componentsProps.popper, + externalSlotProps: slotProps.popper, additionalProps: { anchorEl: buttonRef.current, disablePortal: true, @@ -262,25 +262,6 @@ MultiSelectUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the Select. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes /* @typescript-to-proptypes-ignore */.shape({ - Listbox: PropTypes.elementType, - Popper: PropTypes.elementType, - Root: PropTypes.elementType, - }), - /** - * The props used for each slot inside the Input. - * @default {} - */ - componentsProps: PropTypes.shape({ - listbox: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - popper: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * If `true`, the select will be initially open. * @default false @@ -338,6 +319,25 @@ MultiSelectUnstyled.propTypes /* remove-proptypes */ = { * Function that customizes the rendering of the selected values. */ renderValue: PropTypes.func, + /** + * The props used for each slot inside the MultiSelect. + * @default {} + */ + slotProps: PropTypes.shape({ + listbox: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + popper: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the MultiSelect. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes /* @typescript-to-proptypes-ignore */.shape({ + listbox: PropTypes.elementType, + popper: PropTypes.elementType, + root: PropTypes.elementType, + }), /** * The selected values. * Set to an empty array to deselect all options. diff --git a/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.types.ts b/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.types.ts index d444fa3e7a9874..ace94ab30b0688 100644 --- a/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.types.ts +++ b/packages/mui-base/src/MultiSelectUnstyled/MultiSelectUnstyled.types.ts @@ -12,37 +12,6 @@ import { SlotComponentProps } from '../utils'; export interface MultiSelectUnstyledComponentsPropsOverrides {} export interface MultiSelectUnstyledOwnProps extends SelectUnstyledCommonProps { - /** - * The components used for each slot inside the Select. - * Either a string to use a HTML element or a component. - * @default {} - */ - components?: { - Root?: React.ElementType; - Listbox?: React.ElementType; - Popper?: React.ComponentType>; - }; - /** - * The props used for each slot inside the Input. - * @default {} - */ - componentsProps?: { - root?: SlotComponentProps< - 'button', - MultiSelectUnstyledComponentsPropsOverrides, - MultiSelectUnstyledOwnerState - >; - listbox?: SlotComponentProps< - 'button', - MultiSelectUnstyledComponentsPropsOverrides, - MultiSelectUnstyledOwnerState - >; - popper?: SlotComponentProps< - typeof PopperUnstyled, - MultiSelectUnstyledComponentsPropsOverrides, - MultiSelectUnstyledOwnerState - >; - }; /** * The default selected values. Use when the component is not controlled. * @default [] @@ -75,6 +44,37 @@ export interface MultiSelectUnstyledOwnProps extends SelectUn * Function that customizes the rendering of the selected values. */ renderValue?: (option: SelectOption[]) => React.ReactNode; + /** + * The props used for each slot inside the MultiSelect. + * @default {} + */ + slotProps?: { + root?: SlotComponentProps< + 'button', + MultiSelectUnstyledComponentsPropsOverrides, + MultiSelectUnstyledOwnerState + >; + listbox?: SlotComponentProps< + 'button', + MultiSelectUnstyledComponentsPropsOverrides, + MultiSelectUnstyledOwnerState + >; + popper?: SlotComponentProps< + typeof PopperUnstyled, + MultiSelectUnstyledComponentsPropsOverrides, + MultiSelectUnstyledOwnerState + >; + }; + /** + * The components used for each slot inside the MultiSelect. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots?: { + root?: React.ElementType; + listbox?: React.ElementType; + popper?: React.ComponentType>; + }; /** * The selected values. * Set to an empty array to deselect all options. diff --git a/packages/mui-base/src/OptionGroupUnstyled/OptionGroupUnstyled.spec.tsx b/packages/mui-base/src/OptionGroupUnstyled/OptionGroupUnstyled.spec.tsx index b261bc7a33730d..1d31617324426e 100644 --- a/packages/mui-base/src/OptionGroupUnstyled/OptionGroupUnstyled.spec.tsx +++ b/packages/mui-base/src/OptionGroupUnstyled/OptionGroupUnstyled.spec.tsx @@ -27,7 +27,7 @@ const List = React.forwardRef(function List( return

  • ; }); -const option = ; +const option = ; const polymorphicComponentTest = () => { const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> = () =>
    ; diff --git a/packages/mui-base/src/OptionGroupUnstyled/OptionGroupUnstyled.tsx b/packages/mui-base/src/OptionGroupUnstyled/OptionGroupUnstyled.tsx index eff4b3c7f7d464..4096b4df065392 100644 --- a/packages/mui-base/src/OptionGroupUnstyled/OptionGroupUnstyled.tsx +++ b/packages/mui-base/src/OptionGroupUnstyled/OptionGroupUnstyled.tsx @@ -36,17 +36,17 @@ function useUtilityClasses(disabled: boolean) { const OptionGroupUnstyled = React.forwardRef(function OptionGroupUnstyled< BaseComponentType extends React.ElementType = OptionGroupUnstyledTypeMap['defaultComponent'], >(props: OptionGroupUnstyledProps, ref: React.ForwardedRef) { - const { component, components = {}, disabled = false, componentsProps = {}, ...other } = props; + const { component, disabled = false, slotProps = {}, slots = {}, ...other } = props; - const Root = component || components?.Root || 'li'; - const Label = components?.Label || 'span'; - const List = components?.List || 'ul'; + const Root = component || slots?.root || 'li'; + const Label = slots?.label || 'span'; + const List = slots?.list || 'ul'; const classes = useUtilityClasses(disabled); const rootProps: WithOptionalOwnerState = useSlotProps({ elementType: Root, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, additionalProps: { ref, @@ -57,14 +57,14 @@ const OptionGroupUnstyled = React.forwardRef(function OptionGroupUnstyled< const labelProps: WithOptionalOwnerState = useSlotProps({ elementType: Label, - externalSlotProps: componentsProps.label, + externalSlotProps: slotProps.label, ownerState: props, className: classes.label, }); const listProps: WithOptionalOwnerState = useSlotProps({ elementType: List, - externalSlotProps: componentsProps.list, + externalSlotProps: slotProps.list, ownerState: props, className: classes.list, }); @@ -92,33 +92,33 @@ OptionGroupUnstyled.propTypes /* remove-proptypes */ = { */ component: PropTypes.elementType, /** - * The components used for each slot inside the OptionGroupUnstyled. - * Either a string to use a HTML element or a component. - * @default {} + * If `true` all the options in the group will be disabled. + * @default false */ - components: PropTypes.shape({ - Label: PropTypes.elementType, - List: PropTypes.elementType, - Root: PropTypes.elementType, - }), + disabled: PropTypes.bool, + /** + * The human-readable description of the group. + */ + label: PropTypes.node, /** * The props used for each slot inside the Input. * @default {} */ - componentsProps: PropTypes.shape({ + slotProps: PropTypes.shape({ label: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), list: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), }), /** - * If `true` all the options in the group will be disabled. - * @default false - */ - disabled: PropTypes.bool, - /** - * The human-readable description of the group. + * The components used for each slot inside the OptionGroupUnstyled. + * Either a string to use a HTML element or a component. + * @default {} */ - label: PropTypes.node, + slots: PropTypes.shape({ + label: PropTypes.elementType, + list: PropTypes.elementType, + root: PropTypes.elementType, + }), } as any; export default OptionGroupUnstyled; diff --git a/packages/mui-base/src/OptionGroupUnstyled/OptionGroupUnstyled.types.ts b/packages/mui-base/src/OptionGroupUnstyled/OptionGroupUnstyled.types.ts index 73693604369862..4e66e0a5b03013 100644 --- a/packages/mui-base/src/OptionGroupUnstyled/OptionGroupUnstyled.types.ts +++ b/packages/mui-base/src/OptionGroupUnstyled/OptionGroupUnstyled.types.ts @@ -21,16 +21,16 @@ export interface OptionGroupUnstyledOwnProps { * Either a string to use a HTML element or a component. * @default {} */ - components?: { - Root?: React.ElementType; - Label?: React.ElementType; - List?: React.ElementType; + slots?: { + root?: React.ElementType; + label?: React.ElementType; + list?: React.ElementType; }; /** * The props used for each slot inside the Input. * @default {} */ - componentsProps?: { + slotProps?: { root?: SlotComponentProps< 'li', OptionGroupUnstyledComponentsPropsOverrides, diff --git a/packages/mui-base/src/OptionUnstyled/OptionUnstyled.spec.tsx b/packages/mui-base/src/OptionUnstyled/OptionUnstyled.spec.tsx index d27bbc86f40851..e3d342379479d9 100644 --- a/packages/mui-base/src/OptionUnstyled/OptionUnstyled.spec.tsx +++ b/packages/mui-base/src/OptionUnstyled/OptionUnstyled.spec.tsx @@ -11,7 +11,7 @@ const Root = React.forwardRef(function Root( return
  • ; }); -const option = ; +const option = ; const polymorphicComponentTest = () => { const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> = () =>
    ; diff --git a/packages/mui-base/src/OptionUnstyled/OptionUnstyled.tsx b/packages/mui-base/src/OptionUnstyled/OptionUnstyled.tsx index 555054b1444c99..297a89c379e410 100644 --- a/packages/mui-base/src/OptionUnstyled/OptionUnstyled.tsx +++ b/packages/mui-base/src/OptionUnstyled/OptionUnstyled.tsx @@ -32,11 +32,11 @@ const OptionUnstyled = React.forwardRef(function OptionUnstyled( const { children, component, - components = {}, - componentsProps = {}, disabled, - value, label, + slotProps = {}, + slots = {}, + value, ...other } = props; @@ -45,7 +45,7 @@ const OptionUnstyled = React.forwardRef(function OptionUnstyled( throw new Error('OptionUnstyled must be used within a SelectUnstyled'); } - const Root = component || components.Root || 'li'; + const Root = component || slots.root || 'li'; const selectOption = { value, @@ -86,7 +86,7 @@ const OptionUnstyled = React.forwardRef(function OptionUnstyled( const rootProps = useSlotProps({ elementType: Root, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, additionalProps: { ...optionProps, @@ -113,21 +113,6 @@ OptionUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the OptionUnstyled. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Root: PropTypes.elementType, - }), - /** - * The props used for each slot inside the OptionUnstyled. - * @default {} - */ - componentsProps: PropTypes.shape({ - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * If `true`, the option will be disabled. * @default false @@ -138,6 +123,21 @@ OptionUnstyled.propTypes /* remove-proptypes */ = { * Used for keyboard text navigation matching. */ label: PropTypes.string, + /** + * The props used for each slot inside the OptionUnstyled. + * @default {} + */ + slotProps: PropTypes.shape({ + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the OptionUnstyled. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + root: PropTypes.elementType, + }), /** * The value of the option. */ diff --git a/packages/mui-base/src/OptionUnstyled/OptionUnstyled.types.ts b/packages/mui-base/src/OptionUnstyled/OptionUnstyled.types.ts index 6593b09ba43231..21cb4ab64dd2a9 100644 --- a/packages/mui-base/src/OptionUnstyled/OptionUnstyled.types.ts +++ b/packages/mui-base/src/OptionUnstyled/OptionUnstyled.types.ts @@ -18,25 +18,25 @@ export interface OptionUnstyledOwnProps { */ disabled?: boolean; className?: string; - /** - * The components used for each slot inside the OptionUnstyled. - * Either a string to use a HTML element or a component. - * @default {} - */ - components?: { - Root?: React.ElementType; - }; /** * The props used for each slot inside the OptionUnstyled. * @default {} */ - componentsProps?: { + slotProps?: { root?: SlotComponentProps< 'li', OptionUnstyledComponentsPropsOverrides, OptionUnstyledOwnerState >; }; + /** + * The components used for each slot inside the OptionUnstyled. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots?: { + root?: React.ElementType; + }; /** * A text representation of the option's content. * Used for keyboard text navigation matching. diff --git a/packages/mui-base/src/PopperUnstyled/PopperUnstyled.d.ts b/packages/mui-base/src/PopperUnstyled/PopperUnstyled.d.ts index 99194f05b31645..615fb2e6631766 100644 --- a/packages/mui-base/src/PopperUnstyled/PopperUnstyled.d.ts +++ b/packages/mui-base/src/PopperUnstyled/PopperUnstyled.d.ts @@ -37,25 +37,6 @@ export interface PopperUnstyledOwnProps { * so it's simply `document.body` most of the time. */ container?: PortalProps['container']; - /** - * The components used for each slot inside the Popper. - * Either a string to use a HTML element or a component. - * @default {} - */ - components?: { - Root?: React.ElementType; - }; - /** - * The props used for each slot inside the Popper. - * @default {} - */ - componentsProps?: { - root?: SlotComponentProps< - 'div', - PopperUnstyledComponentsPropsOverrides, - PopperUnstyledOwnerState - >; - }; /** * Direction of the text. * @default 'ltr' @@ -101,6 +82,25 @@ export interface PopperUnstyledOwnProps { * A ref that points to the used popper instance. */ popperRef?: React.Ref; + /** + * The props used for each slot inside the Popper. + * @default {} + */ + slotProps?: { + root?: SlotComponentProps< + 'div', + PopperUnstyledComponentsPropsOverrides, + PopperUnstyledOwnerState + >; + }; + /** + * The components used for each slot inside the Popper. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots?: { + root?: React.ElementType; + }; /** * Help supporting a react-transition-group/Transition component. * @default false diff --git a/packages/mui-base/src/PopperUnstyled/PopperUnstyled.js b/packages/mui-base/src/PopperUnstyled/PopperUnstyled.js index a3445b6927e666..3c1370cd01e625 100644 --- a/packages/mui-base/src/PopperUnstyled/PopperUnstyled.js +++ b/packages/mui-base/src/PopperUnstyled/PopperUnstyled.js @@ -53,8 +53,6 @@ const PopperTooltip = React.forwardRef(function PopperTooltip(props, ref) { anchorEl, children, component, - components = {}, - componentsProps = {}, direction, disablePortal, modifiers, @@ -63,6 +61,8 @@ const PopperTooltip = React.forwardRef(function PopperTooltip(props, ref) { placement: initialPlacement, popperOptions, popperRef: popperRefProp, + slotProps = {}, + slots = {}, TransitionProps, ...other } = props; @@ -175,10 +175,10 @@ const PopperTooltip = React.forwardRef(function PopperTooltip(props, ref) { } const classes = useUtilityClasses(); - const Root = component ?? components.Root ?? 'div'; + const Root = component ?? slots.root ?? 'div'; const rootProps = useSlotProps({ elementType: Root, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, additionalProps: { role: 'tooltip', @@ -338,21 +338,6 @@ PopperUnstyled.propTypes /* remove-proptypes */ = { PropTypes.node, PropTypes.func, ]), - /** - * The components used for each slot inside the Popper. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Root: PropTypes.elementType, - }), - /** - * The props used for each slot inside the Popper. - * @default {} - */ - componentsProps: PropTypes.shape({ - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * An HTML element or function that returns one. * The `container` will have the portal children appended to it. @@ -468,6 +453,21 @@ PopperUnstyled.propTypes /* remove-proptypes */ = { * A ref that points to the used popper instance. */ popperRef: refType, + /** + * The props used for each slot inside the Popper. + * @default {} + */ + slotProps: PropTypes.shape({ + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the Popper. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + root: PropTypes.elementType, + }), /** * @ignore */ diff --git a/packages/mui-base/src/PopperUnstyled/PopperUnstyled.spec.tsx b/packages/mui-base/src/PopperUnstyled/PopperUnstyled.spec.tsx index 559ea3aaad60ca..0db0fb57fa0cec 100644 --- a/packages/mui-base/src/PopperUnstyled/PopperUnstyled.spec.tsx +++ b/packages/mui-base/src/PopperUnstyled/PopperUnstyled.spec.tsx @@ -7,7 +7,7 @@ function Root(props: PopperUnstyledRootSlotProps) { return
    ; } -const styledPopper = ; +const styledPopper = ; const polymorphicComponentTest = () => { const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> = () =>
    ; diff --git a/packages/mui-base/src/PopperUnstyled/PopperUnstyled.test.js b/packages/mui-base/src/PopperUnstyled/PopperUnstyled.test.js index e94182424b6d5d..f9f26f4d9d1d35 100644 --- a/packages/mui-base/src/PopperUnstyled/PopperUnstyled.test.js +++ b/packages/mui-base/src/PopperUnstyled/PopperUnstyled.test.js @@ -1,10 +1,11 @@ import * as React from 'react'; import { expect } from 'chai'; -import { createRenderer, describeConformance, screen } from 'test/utils'; -import PopperUnstyled from '@mui/base/PopperUnstyled'; +import { createRenderer, createMount, describeConformanceUnstyled, screen } from 'test/utils'; +import PopperUnstyled, { popperUnstyledClasses } from '@mui/base/PopperUnstyled'; describe('', () => { const { render } = createRenderer(); + const mount = createMount(); const defaultProps = { anchorEl: () => document.createElement('svg'), @@ -12,17 +13,24 @@ describe('', () => { open: true, }; - describeConformance(, () => ({ - classes: {}, + describeConformanceUnstyled(, () => ({ inheritComponent: 'div', + render, + mount, refInstanceof: window.HTMLDivElement, skip: [ 'themeDefaultProps', 'themeStyleOverrides', 'themeVariants', + 'propsSpread', // https://github.com/facebook/react/issues/11565 'reactTestRenderer', ], + slots: { + root: { + expectedClassName: popperUnstyledClasses.root, + }, + }, })); it('should pass ownerState to overridable component', () => { diff --git a/packages/mui-base/src/PopperUnstyled/index.d.ts b/packages/mui-base/src/PopperUnstyled/index.d.ts index 9eed89eebe9132..0550601a07f062 100644 --- a/packages/mui-base/src/PopperUnstyled/index.d.ts +++ b/packages/mui-base/src/PopperUnstyled/index.d.ts @@ -1,2 +1,5 @@ export { default } from './PopperUnstyled'; export * from './PopperUnstyled'; + +export { default as popperUnstyledClasses } from './popperUnstyledClasses'; +export * from './popperUnstyledClasses'; diff --git a/packages/mui-base/src/PopperUnstyled/index.js b/packages/mui-base/src/PopperUnstyled/index.js index 6dd7dec7c7d756..264df8cd2af84e 100644 --- a/packages/mui-base/src/PopperUnstyled/index.js +++ b/packages/mui-base/src/PopperUnstyled/index.js @@ -1 +1,4 @@ export { default } from './PopperUnstyled'; + +export { default as popperUnstyledClasses } from './popperUnstyledClasses'; +export * from './popperUnstyledClasses'; diff --git a/packages/mui-base/src/SelectUnstyled/SelectUnstyled.spec.tsx b/packages/mui-base/src/SelectUnstyled/SelectUnstyled.spec.tsx index 31e72ccb351d8c..f003f447df6eaa 100644 --- a/packages/mui-base/src/SelectUnstyled/SelectUnstyled.spec.tsx +++ b/packages/mui-base/src/SelectUnstyled/SelectUnstyled.spec.tsx @@ -9,7 +9,7 @@ import { const SelectUnstyledComponentsPropsOverridesTest = ( (props: SelectUnstyledPopperSlotProps ); const SelectUnstyledPopperComponentOverridesTest = ( ); @@ -61,18 +61,18 @@ function InvalidPopper({ requiredProp }: { requiredProp: string }) { const SelectUnstyledComponentsOverridesUsingInvalidComponentTest = ( ); const SelectUnstyledComponentsOverridesUsingHostComponentTest = ( ); diff --git a/packages/mui-base/src/SelectUnstyled/SelectUnstyled.test.tsx b/packages/mui-base/src/SelectUnstyled/SelectUnstyled.test.tsx index 50afe0f2a96f60..5cdfccc32a55ec 100644 --- a/packages/mui-base/src/SelectUnstyled/SelectUnstyled.test.tsx +++ b/packages/mui-base/src/SelectUnstyled/SelectUnstyled.test.tsx @@ -51,7 +51,7 @@ describe('SelectUnstyled', () => { ['Enter', 'ArrowDown', 'ArrowUp'].forEach((key) => { it(`opens the dropdown when the "${key}" key is down on the button`, () => { // can't use the default native `button` as it doesn't treat enter or space press as a click - const { getByRole } = render(); + const { getByRole } = render(); const button = getByRole('button'); act(() => { button.focus(); @@ -66,7 +66,7 @@ describe('SelectUnstyled', () => { it(`opens the dropdown when the " " key is let go on the button`, () => { // can't use the default native `button` as it doesn't treat enter or space press as a click - const { getByRole } = render(); + const { getByRole } = render(); const button = getByRole('button'); act(() => { button.focus(); diff --git a/packages/mui-base/src/SelectUnstyled/SelectUnstyled.tsx b/packages/mui-base/src/SelectUnstyled/SelectUnstyled.tsx index 5ff44e24006bce..b42399c813f3d5 100644 --- a/packages/mui-base/src/SelectUnstyled/SelectUnstyled.tsx +++ b/packages/mui-base/src/SelectUnstyled/SelectUnstyled.tsx @@ -75,8 +75,6 @@ const SelectUnstyled = React.forwardRef(function SelectUnstyled(null); const listboxRef = React.useRef(null); - const Button = component ?? components.Root ?? 'button'; - const ListboxRoot = components.Listbox ?? 'ul'; - const Popper = components.Popper ?? PopperUnstyled; + const Button = component ?? slots.root ?? 'button'; + const ListboxRoot = slots.listbox ?? 'ul'; + const Popper = slots.popper ?? PopperUnstyled; const handleButtonRefChange = React.useCallback((element: HTMLElement | null) => { setButtonDefined(element != null); @@ -175,7 +175,7 @@ const SelectUnstyled = React.forwardRef(function SelectUnstyled> = useSlotProps({ elementType: Button, getSlotProps: getButtonProps, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, ownerState, className: classes.root, @@ -185,7 +185,7 @@ const SelectUnstyled = React.forwardRef(function SelectUnstyled = useSlotProps({ elementType: Popper, - externalSlotProps: componentsProps.popper, + externalSlotProps: slotProps.popper, additionalProps: { anchorEl: buttonRef.current, disablePortal: true, @@ -251,25 +251,6 @@ SelectUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the Select. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes /* @typescript-to-proptypes-ignore */.shape({ - Listbox: PropTypes.elementType, - Popper: PropTypes.elementType, - Root: PropTypes.elementType, - }), - /** - * The props used for each slot inside the Input. - * @default {} - */ - componentsProps: PropTypes.shape({ - listbox: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - popper: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * If `true`, the select will be initially open. * @default false @@ -326,6 +307,25 @@ SelectUnstyled.propTypes /* remove-proptypes */ = { * Function that customizes the rendering of the selected value. */ renderValue: PropTypes.func, + /** + * The props used for each slot inside the Input. + * @default {} + */ + slotProps: PropTypes.shape({ + listbox: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + popper: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the Select. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes /* @typescript-to-proptypes-ignore */.shape({ + listbox: PropTypes.elementType, + popper: PropTypes.elementType, + root: PropTypes.elementType, + }), /** * The selected value. * Set to `null` to deselect all options. diff --git a/packages/mui-base/src/SelectUnstyled/SelectUnstyled.types.ts b/packages/mui-base/src/SelectUnstyled/SelectUnstyled.types.ts index dc00e6a6586586..c958521de71771 100644 --- a/packages/mui-base/src/SelectUnstyled/SelectUnstyled.types.ts +++ b/packages/mui-base/src/SelectUnstyled/SelectUnstyled.types.ts @@ -51,37 +51,6 @@ export interface SelectUnstyledCommonProps { } export interface SelectUnstyledOwnProps extends SelectUnstyledCommonProps { - /** - * The components used for each slot inside the Select. - * Either a string to use a HTML element or a component. - * @default {} - */ - components?: { - Root?: React.ElementType; - Listbox?: React.ElementType; - Popper?: React.ComponentType>; - }; - /** - * The props used for each slot inside the Input. - * @default {} - */ - componentsProps?: { - root?: SlotComponentProps< - 'button', - SelectUnstyledComponentsPropsOverrides, - SelectUnstyledOwnerState - >; - listbox?: SlotComponentProps< - 'button', - SelectUnstyledComponentsPropsOverrides, - SelectUnstyledOwnerState - >; - popper?: SlotComponentProps< - typeof PopperUnstyled, - SelectUnstyledComponentsPropsOverrides, - SelectUnstyledOwnerState - >; - }; /** * The default selected value. Use when the component is not controlled. */ @@ -113,6 +82,37 @@ export interface SelectUnstyledOwnProps extends SelectUnstyle * Function that customizes the rendering of the selected value. */ renderValue?: (option: SelectOption | null) => React.ReactNode; + /** + * The props used for each slot inside the Input. + * @default {} + */ + slotProps?: { + root?: SlotComponentProps< + 'button', + SelectUnstyledComponentsPropsOverrides, + SelectUnstyledOwnerState + >; + listbox?: SlotComponentProps< + 'button', + SelectUnstyledComponentsPropsOverrides, + SelectUnstyledOwnerState + >; + popper?: SlotComponentProps< + typeof PopperUnstyled, + SelectUnstyledComponentsPropsOverrides, + SelectUnstyledOwnerState + >; + }; + /** + * The components used for each slot inside the Select. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots?: { + root?: React.ElementType; + listbox?: React.ElementType; + popper?: React.ComponentType>; + }; /** * The selected value. * Set to `null` to deselect all options. diff --git a/packages/mui-base/src/SliderUnstyled/SliderUnstyled.js b/packages/mui-base/src/SliderUnstyled/SliderUnstyled.js index c2c1c4dd21b5d4..553c786477efc9 100644 --- a/packages/mui-base/src/SliderUnstyled/SliderUnstyled.js +++ b/packages/mui-base/src/SliderUnstyled/SliderUnstyled.js @@ -69,8 +69,8 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) { valueLabelDisplay = 'off', valueLabelFormat = Identity, isRtl = false, - components = {}, - componentsProps = {}, + slotProps = {}, + slots = {}, ...other } = props; @@ -115,28 +115,28 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) { const classes = useUtilityClasses(ownerState); - const Root = component ?? components.Root ?? 'span'; + const Root = component ?? slots.root ?? 'span'; const rootProps = useSlotProps({ elementType: Root, getSlotProps: getRootProps, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, ownerState, className: [classes.root, className], }); - const Rail = components.Rail ?? 'span'; + const Rail = slots.rail ?? 'span'; const railProps = useSlotProps({ elementType: Rail, - externalSlotProps: componentsProps.rail, + externalSlotProps: slotProps.rail, ownerState, className: classes.rail, }); - const Track = components.Track ?? 'span'; + const Track = slots.track ?? 'span'; const trackProps = useSlotProps({ elementType: Track, - externalSlotProps: componentsProps.track, + externalSlotProps: slotProps.track, additionalProps: { style: { ...axisProps[axis].offset(trackOffset), @@ -147,41 +147,41 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) { className: classes.track, }); - const Thumb = components.Thumb ?? 'span'; + const Thumb = slots.thumb ?? 'span'; const thumbProps = useSlotProps({ elementType: Thumb, getSlotProps: getThumbProps, - externalSlotProps: componentsProps.thumb, + externalSlotProps: slotProps.thumb, ownerState, }); - const ValueLabel = components.ValueLabel ?? SliderValueLabelUnstyled; + const ValueLabel = slots.valueLabel ?? SliderValueLabelUnstyled; const valueLabelProps = useSlotProps({ elementType: ValueLabel, - externalSlotProps: componentsProps.valueLabel, + externalSlotProps: slotProps.valueLabel, ownerState, }); - const Mark = components.Mark ?? 'span'; + const Mark = slots.mark ?? 'span'; const markProps = useSlotProps({ elementType: Mark, - externalSlotProps: componentsProps.mark, + externalSlotProps: slotProps.mark, ownerState, className: classes.mark, }); - const MarkLabel = components.MarkLabel ?? 'span'; + const MarkLabel = slots.markLabel ?? 'span'; const markLabelProps = useSlotProps({ elementType: MarkLabel, - externalSlotProps: componentsProps.markLabel, + externalSlotProps: slotProps.markLabel, ownerState, }); - const Input = components.Input || 'input'; + const Input = slots.input || 'input'; const inputProps = useSlotProps({ elementType: Input, getSlotProps: getHiddenInputProps, - externalSlotProps: componentsProps.input, + externalSlotProps: slotProps.input, ownerState, }); @@ -353,48 +353,6 @@ SliderUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the Slider. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Input: PropTypes.elementType, - Mark: PropTypes.elementType, - MarkLabel: PropTypes.elementType, - Rail: PropTypes.elementType, - Root: PropTypes.elementType, - Thumb: PropTypes.elementType, - Track: PropTypes.elementType, - ValueLabel: PropTypes.elementType, - }), - /** - * The props used for each slot inside the Slider. - * @default {} - */ - componentsProps: PropTypes.shape({ - input: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - mark: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - markLabel: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - rail: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - thumb: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - track: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - valueLabel: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.shape({ - children: PropTypes.element, - className: PropTypes.string, - components: PropTypes.shape({ - Root: PropTypes.elementType, - }), - open: PropTypes.bool, - style: PropTypes.object, - value: PropTypes.number, - valueLabelDisplay: PropTypes.oneOf(['auto', 'off', 'on']), - }), - ]), - }), /** * The default value. Use when the component is not controlled. */ @@ -487,6 +445,45 @@ SliderUnstyled.propTypes /* remove-proptypes */ = { * @default (x) => x */ scale: PropTypes.func, + /** + * The props used for each slot inside the Slider. + * @default {} + */ + slotProps: PropTypes.shape({ + input: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + mark: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + markLabel: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + rail: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + thumb: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + track: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + valueLabel: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.shape({ + children: PropTypes.element, + className: PropTypes.string, + open: PropTypes.bool, + style: PropTypes.object, + value: PropTypes.number, + valueLabelDisplay: PropTypes.oneOf(['auto', 'off', 'on']), + }), + ]), + }), + /** + * The components used for each slot inside the Slider. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + input: PropTypes.elementType, + mark: PropTypes.elementType, + markLabel: PropTypes.elementType, + rail: PropTypes.elementType, + root: PropTypes.elementType, + thumb: PropTypes.elementType, + track: PropTypes.elementType, + valueLabel: PropTypes.elementType, + }), /** * The granularity with which the slider can step through values. (A "discrete" slider.) * The `min` prop serves as the origin for the valid values. diff --git a/packages/mui-base/src/SliderUnstyled/SliderUnstyled.spec.tsx b/packages/mui-base/src/SliderUnstyled/SliderUnstyled.spec.tsx index eb199868af4c7f..564be2c6a9ab36 100644 --- a/packages/mui-base/src/SliderUnstyled/SliderUnstyled.spec.tsx +++ b/packages/mui-base/src/SliderUnstyled/SliderUnstyled.spec.tsx @@ -75,7 +75,11 @@ const Input = React.forwardRef(function Input( return ; }); -const styledSlider = ; +const styledSlider = ( + +); const polymorphicComponentTest = () => { const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> = () =>
    ; diff --git a/packages/mui-base/src/SliderUnstyled/SliderUnstyled.test.js b/packages/mui-base/src/SliderUnstyled/SliderUnstyled.test.js index c980e55dd3edc1..a8f708e4a59d99 100644 --- a/packages/mui-base/src/SliderUnstyled/SliderUnstyled.test.js +++ b/packages/mui-base/src/SliderUnstyled/SliderUnstyled.test.js @@ -68,7 +68,7 @@ describe('', () => { }, ); - render(); + render(); expect(ownerState).not.to.equal(null); expect(theme).not.to.equal(null); @@ -78,8 +78,8 @@ describe('', () => { const elementRef = React.createRef(); render( , diff --git a/packages/mui-base/src/SliderUnstyled/SliderUnstyled.types.ts b/packages/mui-base/src/SliderUnstyled/SliderUnstyled.types.ts index ae34df178de9e3..734b3896152643 100644 --- a/packages/mui-base/src/SliderUnstyled/SliderUnstyled.types.ts +++ b/packages/mui-base/src/SliderUnstyled/SliderUnstyled.types.ts @@ -51,68 +51,6 @@ export interface SliderUnstyledOwnProps { * Override or extend the styles applied to the component. */ classes?: Partial; - /** - * The components used for each slot inside the Slider. - * Either a string to use a HTML element or a component. - * @default {} - */ - components?: { - Root?: React.ElementType; - Track?: React.ElementType; - Rail?: React.ElementType; - Thumb?: React.ElementType; - Mark?: React.ElementType; - MarkLabel?: React.ElementType; - ValueLabel?: React.ElementType; - Input?: React.ElementType; - }; - /** - * The props used for each slot inside the Slider. - * @default {} - */ - componentsProps?: { - root?: SlotComponentProps< - 'span', - SliderUnstyledComponentsPropsOverrides, - SliderUnstyledOwnerState - >; - track?: SlotComponentProps< - 'span', - SliderUnstyledComponentsPropsOverrides, - SliderUnstyledOwnerState - >; - rail?: SlotComponentProps< - 'span', - SliderUnstyledComponentsPropsOverrides, - SliderUnstyledOwnerState - >; - thumb?: SlotComponentProps< - 'span', - SliderUnstyledComponentsPropsOverrides, - SliderUnstyledOwnerState - >; - mark?: SlotComponentProps< - 'span', - SliderUnstyledComponentsPropsOverrides, - SliderUnstyledOwnerState - >; - markLabel?: SlotComponentProps< - 'span', - SliderUnstyledComponentsPropsOverrides, - SliderUnstyledOwnerState - >; - valueLabel?: SlotComponentProps< - typeof SliderValueLabelUnstyled, - SliderUnstyledComponentsPropsOverrides, - SliderUnstyledOwnerState - >; - - input?: SlotComponentProps< - 'input', - SliderUnstyledComponentsPropsOverrides, - SliderUnstyledOwnerState - >; - }; /** * The default value. Use when the component is not controlled. */ @@ -197,6 +135,68 @@ export interface SliderUnstyledOwnProps { * @default (x) => x */ scale?: (value: number) => number; + /** + * The props used for each slot inside the Slider. + * @default {} + */ + slotProps?: { + root?: SlotComponentProps< + 'span', + SliderUnstyledComponentsPropsOverrides, + SliderUnstyledOwnerState + >; + track?: SlotComponentProps< + 'span', + SliderUnstyledComponentsPropsOverrides, + SliderUnstyledOwnerState + >; + rail?: SlotComponentProps< + 'span', + SliderUnstyledComponentsPropsOverrides, + SliderUnstyledOwnerState + >; + thumb?: SlotComponentProps< + 'span', + SliderUnstyledComponentsPropsOverrides, + SliderUnstyledOwnerState + >; + mark?: SlotComponentProps< + 'span', + SliderUnstyledComponentsPropsOverrides, + SliderUnstyledOwnerState + >; + markLabel?: SlotComponentProps< + 'span', + SliderUnstyledComponentsPropsOverrides, + SliderUnstyledOwnerState + >; + valueLabel?: SlotComponentProps< + typeof SliderValueLabelUnstyled, + SliderUnstyledComponentsPropsOverrides, + SliderUnstyledOwnerState + >; + + input?: SlotComponentProps< + 'input', + SliderUnstyledComponentsPropsOverrides, + SliderUnstyledOwnerState + >; + }; + /** + * The components used for each slot inside the Slider. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots?: { + root?: React.ElementType; + track?: React.ElementType; + rail?: React.ElementType; + thumb?: React.ElementType; + mark?: React.ElementType; + markLabel?: React.ElementType; + valueLabel?: React.ElementType; + input?: React.ElementType; + }; /** * The granularity with which the slider can step through values. (A "discrete" slider.) * The `min` prop serves as the origin for the valid values. diff --git a/packages/mui-base/src/SliderUnstyled/SliderValueLabelUnstyled.d.ts b/packages/mui-base/src/SliderUnstyled/SliderValueLabelUnstyled.d.ts index 4ff85e1a12e65b..1be5a15bde3f43 100644 --- a/packages/mui-base/src/SliderUnstyled/SliderValueLabelUnstyled.d.ts +++ b/packages/mui-base/src/SliderUnstyled/SliderValueLabelUnstyled.d.ts @@ -4,14 +4,6 @@ export interface SliderValueLabelUnstyledProps { children?: React.ReactElement; className?: string; style?: React.CSSProperties; - /** - * The components used for each slot inside the ValueLabel. - * Either a string to use a HTML element or a component. - * @default {} - */ - components?: { - Root?: React.ElementType; - }; /** * If `true`, the value label is visible. */ diff --git a/packages/mui-base/src/SnackbarUnstyled/SnackbarUnstyled.spec.tsx b/packages/mui-base/src/SnackbarUnstyled/SnackbarUnstyled.spec.tsx index 4bdc28d063f4bc..cd799c3c2d1cd3 100644 --- a/packages/mui-base/src/SnackbarUnstyled/SnackbarUnstyled.spec.tsx +++ b/packages/mui-base/src/SnackbarUnstyled/SnackbarUnstyled.spec.tsx @@ -16,5 +16,5 @@ const Root = React.forwardRef( ); const SnackbarUnstyledWithCustomRoot = (props: SnackbarUnstyledProps) => { - return ; + return ; }; diff --git a/packages/mui-base/src/SnackbarUnstyled/SnackbarUnstyled.tsx b/packages/mui-base/src/SnackbarUnstyled/SnackbarUnstyled.tsx index 9999fa651710e2..97e1b82f2922ad 100644 --- a/packages/mui-base/src/SnackbarUnstyled/SnackbarUnstyled.tsx +++ b/packages/mui-base/src/SnackbarUnstyled/SnackbarUnstyled.tsx @@ -39,8 +39,6 @@ const SnackbarUnstyled = React.forwardRef(function SnackbarUnstyled( autoHideDuration = null, children, component, - components = {}, - componentsProps = {}, disableWindowBlurListener = false, exited = true, onBlur, @@ -50,6 +48,8 @@ const SnackbarUnstyled = React.forwardRef(function SnackbarUnstyled( onMouseLeave, open, resumeHideDuration, + slotProps = {}, + slots = {}, ...other } = props; @@ -67,13 +67,13 @@ const SnackbarUnstyled = React.forwardRef(function SnackbarUnstyled( const ownerState: SnackbarUnstyledOwnerState = props; - const Root = component || components.Root || 'div'; + const Root = component || slots.root || 'div'; const rootProps: WithOptionalOwnerState = useSlotProps({ elementType: Root, getSlotProps: getRootProps, externalForwardedProps: other, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, additionalProps: { ref, }, @@ -85,7 +85,7 @@ const SnackbarUnstyled = React.forwardRef(function SnackbarUnstyled( Omit > = useSlotProps({ elementType: ClickAwayListener, - externalSlotProps: componentsProps.clickAwayListener, + externalSlotProps: slotProps.clickAwayListener, additionalProps: { onClickAway, }, @@ -129,38 +129,6 @@ SnackbarUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the Snackbar. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Root: PropTypes.elementType, - }), - /** - * The props used for each slot inside the Snackbar. - * @default {} - */ - componentsProps: PropTypes.shape({ - clickAwayListener: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.shape({ - children: PropTypes.element.isRequired, - disableReactTree: PropTypes.bool, - mouseEvent: PropTypes.oneOf([ - 'onClick', - 'onMouseDown', - 'onMouseUp', - 'onPointerDown', - 'onPointerUp', - false, - ]), - onClickAway: PropTypes.func, - touchEvent: PropTypes.oneOf(['onTouchEnd', 'onTouchStart', false]), - }), - ]), - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * If `true`, the `autoHideDuration` timer will expire even if the window is not focused. * @default false @@ -209,6 +177,38 @@ SnackbarUnstyled.propTypes /* remove-proptypes */ = { * we default to `autoHideDuration / 2` ms. */ resumeHideDuration: PropTypes.number, + /** + * The props used for each slot inside the Snackbar. + * @default {} + */ + slotProps: PropTypes.shape({ + clickAwayListener: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.shape({ + children: PropTypes.element.isRequired, + disableReactTree: PropTypes.bool, + mouseEvent: PropTypes.oneOf([ + 'onClick', + 'onMouseDown', + 'onMouseUp', + 'onPointerDown', + 'onPointerUp', + false, + ]), + onClickAway: PropTypes.func, + touchEvent: PropTypes.oneOf(['onTouchEnd', 'onTouchStart', false]), + }), + ]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the Snackbar. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + root: PropTypes.elementType, + }), } as any; export default SnackbarUnstyled; diff --git a/packages/mui-base/src/SnackbarUnstyled/SnackbarUnstyled.types.ts b/packages/mui-base/src/SnackbarUnstyled/SnackbarUnstyled.types.ts index ad866690b61522..b423c13212f9f5 100644 --- a/packages/mui-base/src/SnackbarUnstyled/SnackbarUnstyled.types.ts +++ b/packages/mui-base/src/SnackbarUnstyled/SnackbarUnstyled.types.ts @@ -13,14 +13,14 @@ export interface SnackbarUnstyledOwnProps extends Omit; }); -const styledSwitch = ; +const styledSwitch = ( + +); const polymorphicComponentTest = () => { const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> = () =>
    ; diff --git a/packages/mui-base/src/SwitchUnstyled/SwitchUnstyled.test.tsx b/packages/mui-base/src/SwitchUnstyled/SwitchUnstyled.test.tsx index fc8686f9de2682..641f91c0ec18e3 100644 --- a/packages/mui-base/src/SwitchUnstyled/SwitchUnstyled.test.tsx +++ b/packages/mui-base/src/SwitchUnstyled/SwitchUnstyled.test.tsx @@ -59,15 +59,13 @@ describe('', () => { }, ); - const components = { - Root: CustomSlot, - Input: CustomSlot, - Thumb: CustomSlot, + const slots = { + root: CustomSlot, + input: CustomSlot, + thumb: CustomSlot, }; - const { getAllByTestId } = render( - , - ); + const { getAllByTestId } = render(); const renderedComponents = getAllByTestId('custom'); expect(renderedComponents.length).to.equal(3); diff --git a/packages/mui-base/src/SwitchUnstyled/SwitchUnstyled.tsx b/packages/mui-base/src/SwitchUnstyled/SwitchUnstyled.tsx index c5e7315359ae5c..c3187a5d020934 100644 --- a/packages/mui-base/src/SwitchUnstyled/SwitchUnstyled.tsx +++ b/packages/mui-base/src/SwitchUnstyled/SwitchUnstyled.tsx @@ -51,8 +51,6 @@ const SwitchUnstyled = React.forwardRef(function SwitchUnstyled< const { checked: checkedProp, component, - components = {}, - componentsProps = {}, defaultChecked, disabled: disabledProp, onBlur, @@ -61,6 +59,8 @@ const SwitchUnstyled = React.forwardRef(function SwitchUnstyled< onFocusVisible, readOnly: readOnlyProp, required, + slotProps = {}, + slots = {}, ...other } = props; @@ -87,10 +87,10 @@ const SwitchUnstyled = React.forwardRef(function SwitchUnstyled< const classes = useUtilityClasses(ownerState); - const Root: React.ElementType = component ?? components.Root ?? 'span'; + const Root: React.ElementType = component ?? slots.root ?? 'span'; const rootProps: WithOptionalOwnerState = useSlotProps({ elementType: Root, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, additionalProps: { ref, @@ -99,28 +99,27 @@ const SwitchUnstyled = React.forwardRef(function SwitchUnstyled< className: classes.root, }); - const Thumb: React.ElementType = components.Thumb ?? 'span'; + const Thumb: React.ElementType = slots.thumb ?? 'span'; const thumbProps: WithOptionalOwnerState = useSlotProps({ elementType: Thumb, - externalSlotProps: componentsProps.thumb, + externalSlotProps: slotProps.thumb, ownerState, className: classes.thumb, }); - const Input: React.ElementType = components.Input ?? 'input'; + const Input: React.ElementType = slots.input ?? 'input'; const inputProps: WithOptionalOwnerState = useSlotProps({ elementType: Input, getSlotProps: getInputProps, - externalSlotProps: componentsProps.input, + externalSlotProps: slotProps.input, ownerState, className: classes.input, }); - const Track: React.ElementType = - components.Track === null ? () => null : components.Track ?? 'span'; + const Track: React.ElementType = slots.track === null ? () => null : slots.track ?? 'span'; const trackProps: WithOptionalOwnerState = useSlotProps({ elementType: Track, - externalSlotProps: componentsProps.track, + externalSlotProps: slotProps.track, ownerState, className: classes.track, }); @@ -152,27 +151,6 @@ SwitchUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the Switch. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes /* @typescript-to-proptypes-ignore */.shape({ - Input: PropTypes.elementType, - Root: PropTypes.elementType, - Thumb: PropTypes.elementType, - Track: PropTypes.oneOfType([PropTypes.elementType, PropTypes.oneOf([null])]), - }), - /** - * The props used for each slot inside the Switch. - * @default {} - */ - componentsProps: PropTypes.shape({ - input: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - thumb: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - track: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * The default checked state. Use when the component is not controlled. */ @@ -209,6 +187,27 @@ SwitchUnstyled.propTypes /* remove-proptypes */ = { * If `true`, the `input` element is required. */ required: PropTypes.bool, + /** + * The props used for each slot inside the Switch. + * @default {} + */ + slotProps: PropTypes.shape({ + input: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + thumb: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + track: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the Switch. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes /* @typescript-to-proptypes-ignore */.shape({ + input: PropTypes.elementType, + root: PropTypes.elementType, + thumb: PropTypes.elementType, + track: PropTypes.oneOfType([PropTypes.elementType, PropTypes.oneOf([null])]), + }), } as any; export default SwitchUnstyled; diff --git a/packages/mui-base/src/SwitchUnstyled/SwitchUnstyled.types.ts b/packages/mui-base/src/SwitchUnstyled/SwitchUnstyled.types.ts index bc3f0428923652..a71e364eb23532 100644 --- a/packages/mui-base/src/SwitchUnstyled/SwitchUnstyled.types.ts +++ b/packages/mui-base/src/SwitchUnstyled/SwitchUnstyled.types.ts @@ -14,18 +14,18 @@ export interface SwitchUnstyledOwnProps extends UseSwitchParameters { * Either a string to use a HTML element or a component. * @default {} */ - components?: { - Root?: React.ElementType; - Thumb?: React.ElementType; - Input?: React.ElementType; - Track?: React.ElementType | null; + slots?: { + root?: React.ElementType; + thumb?: React.ElementType; + input?: React.ElementType; + track?: React.ElementType | null; }; /** * The props used for each slot inside the Switch. * @default {} */ - componentsProps?: { + slotProps?: { root?: SlotComponentProps< 'span', SwitchUnstyledComponentsPropsOverrides, diff --git a/packages/mui-base/src/TabPanelUnstyled/TabPanelUnstyled.spec.tsx b/packages/mui-base/src/TabPanelUnstyled/TabPanelUnstyled.spec.tsx index 90c0afc56f3be1..f8fa3b7a3b910d 100644 --- a/packages/mui-base/src/TabPanelUnstyled/TabPanelUnstyled.spec.tsx +++ b/packages/mui-base/src/TabPanelUnstyled/TabPanelUnstyled.spec.tsx @@ -7,7 +7,7 @@ function Root(props: TabPanelUnstyledRootSlotProps) { return
    ; } -const styledTabPanel = ; +const styledTabPanel = ; const polymorphicComponentTest = () => { const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> = () =>
    ; diff --git a/packages/mui-base/src/TabPanelUnstyled/TabPanelUnstyled.tsx b/packages/mui-base/src/TabPanelUnstyled/TabPanelUnstyled.tsx index cab391928ba5fa..1faa7a3739394f 100644 --- a/packages/mui-base/src/TabPanelUnstyled/TabPanelUnstyled.tsx +++ b/packages/mui-base/src/TabPanelUnstyled/TabPanelUnstyled.tsx @@ -34,7 +34,7 @@ const TabPanelUnstyled = React.forwardRef(functi props, ref, ) { - const { children, value, components = {}, componentsProps = {}, component, ...other } = props; + const { children, component, value, slotProps = {}, slots = {}, ...other } = props; const { hidden, getRootProps } = useTabPanel(props); @@ -45,11 +45,11 @@ const TabPanelUnstyled = React.forwardRef(functi const classes = useUtilityClasses(ownerState); - const TabPanelRoot: React.ElementType = component ?? components.Root ?? 'div'; + const TabPanelRoot: React.ElementType = component ?? slots.root ?? 'div'; const tabPanelRootProps: WithOptionalOwnerState = useSlotProps({ elementType: TabPanelRoot, getSlotProps: getRootProps, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, additionalProps: { role: 'tabpanel', @@ -77,19 +77,19 @@ TabPanelUnstyled.propTypes /* remove-proptypes */ = { */ component: PropTypes.elementType, /** - * The components used for each slot inside the TabPanel. - * Either a string to use a HTML element or a component. + * The props used for each slot inside the TabPanel. * @default {} */ - components: PropTypes.shape({ - Root: PropTypes.elementType, + slotProps: PropTypes.shape({ + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), }), /** - * The props used for each slot inside the TabPanel. + * The components used for each slot inside the TabPanel. + * Either a string to use a HTML element or a component. * @default {} */ - componentsProps: PropTypes.shape({ - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + slots: PropTypes.shape({ + root: PropTypes.elementType, }), /** * The value of the TabPanel. It will be shown when the Tab with the corresponding value is selected. diff --git a/packages/mui-base/src/TabPanelUnstyled/TabPanelUnstyled.types.ts b/packages/mui-base/src/TabPanelUnstyled/TabPanelUnstyled.types.ts index 2f0965e2bde0fd..dda1d467114cad 100644 --- a/packages/mui-base/src/TabPanelUnstyled/TabPanelUnstyled.types.ts +++ b/packages/mui-base/src/TabPanelUnstyled/TabPanelUnstyled.types.ts @@ -20,15 +20,15 @@ export interface TabPanelUnstyledOwnProps { * Either a string to use a HTML element or a component. * @default {} */ - components?: { - Root?: React.ElementType; + slots?: { + root?: React.ElementType; }; /** * The props used for each slot inside the TabPanel. * @default {} */ - componentsProps?: { + slotProps?: { root?: SlotComponentProps< 'div', TabPanelUnstyledComponentsPropsOverrides, diff --git a/packages/mui-base/src/TabUnstyled/TabUnstyled.spec.tsx b/packages/mui-base/src/TabUnstyled/TabUnstyled.spec.tsx index 9442407601760f..02a4aad95bfaef 100644 --- a/packages/mui-base/src/TabUnstyled/TabUnstyled.spec.tsx +++ b/packages/mui-base/src/TabUnstyled/TabUnstyled.spec.tsx @@ -7,7 +7,7 @@ function Root(props: TabUnstyledRootSlotProps) { return
    ; } -const styledTab = ; +const styledTab = ; const polymorphicComponentTest = () => { const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> = () =>
    ; diff --git a/packages/mui-base/src/TabUnstyled/TabUnstyled.tsx b/packages/mui-base/src/TabUnstyled/TabUnstyled.tsx index 0c9f929d76d70c..c66087bb4f60e5 100644 --- a/packages/mui-base/src/TabUnstyled/TabUnstyled.tsx +++ b/packages/mui-base/src/TabUnstyled/TabUnstyled.tsx @@ -41,8 +41,8 @@ const TabUnstyled = React.forwardRef(function TabUnst onClick, onFocus, component, - components = {}, - componentsProps = {}, + slotProps = {}, + slots = {}, ...other } = props; @@ -75,11 +75,11 @@ const TabUnstyled = React.forwardRef(function TabUnst const classes = useUtilityClasses(ownerState); - const TabRoot: React.ElementType = component ?? components.Root ?? 'button'; + const TabRoot: React.ElementType = component ?? slots.root ?? 'button'; const tabRootProps: WithOptionalOwnerState = useSlotProps({ elementType: TabRoot, getSlotProps: getRootProps, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, additionalProps: { ref, @@ -116,21 +116,6 @@ TabUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the Tab. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Root: PropTypes.elementType, - }), - /** - * The props used for each slot inside the Tab. - * @default {} - */ - componentsProps: PropTypes.shape({ - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * If `true`, the component is disabled. * @default false @@ -148,6 +133,21 @@ TabUnstyled.propTypes /* remove-proptypes */ = { * @ignore */ onFocus: PropTypes.func, + /** + * The props used for each slot inside the Tab. + * @default {} + */ + slotProps: PropTypes.shape({ + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the Tab. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + root: PropTypes.elementType, + }), /** * You can provide your own value. Otherwise, we fall back to the child position index. */ diff --git a/packages/mui-base/src/TabUnstyled/TabUnstyled.types.ts b/packages/mui-base/src/TabUnstyled/TabUnstyled.types.ts index b3ef43de7c5908..ad485fd7f157cd 100644 --- a/packages/mui-base/src/TabUnstyled/TabUnstyled.types.ts +++ b/packages/mui-base/src/TabUnstyled/TabUnstyled.types.ts @@ -7,7 +7,7 @@ import { UseTabRootSlotProps } from './useTab.types'; interface TabUnstyledComponentsPropsOverrides {} export interface TabUnstyledOwnProps - extends Omit { + extends Omit { /** * You can provide your own value. Otherwise, we fall back to the child position index. */ @@ -21,14 +21,14 @@ export interface TabUnstyledOwnProps * Either a string to use a HTML element or a component. * @default {} */ - components?: { - Root?: React.ElementType; + slots?: { + root?: React.ElementType; }; /** * The props used for each slot inside the Tab. * @default {} */ - componentsProps?: { + slotProps?: { root?: SlotComponentProps<'div', TabUnstyledComponentsPropsOverrides, TabUnstyledOwnerState>; }; } diff --git a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationActionsUnstyled.spec.tsx b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationActionsUnstyled.spec.tsx index 3ea4548be7dbad..3263e323883136 100644 --- a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationActionsUnstyled.spec.tsx +++ b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationActionsUnstyled.spec.tsx @@ -18,12 +18,12 @@ function Button(props: TablePaginationActionsUnstyledButtonSlotProps) { const styledTablePaginationActions = ( ''} diff --git a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationActionsUnstyled.tsx b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationActionsUnstyled.tsx index af0bc0822491be..f283d6990e1fbc 100644 --- a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationActionsUnstyled.tsx +++ b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationActionsUnstyled.tsx @@ -35,8 +35,6 @@ const TablePaginationActionsUnstyled = React.forwardRef< >(function TablePaginationActionsUnstyled(props, ref) { const { component, - components = {}, - componentsProps = {}, count, getItemAriaLabel = defaultGetAriaLabel, onPageChange, @@ -47,6 +45,8 @@ const TablePaginationActionsUnstyled = React.forwardRef< direction, // @ts-ignore ownerState: ownerStateProp, + slotProps = {}, + slots = {}, ...other } = props; @@ -68,21 +68,21 @@ const TablePaginationActionsUnstyled = React.forwardRef< onPageChange(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1)); }; - const Root = components.Root ?? component ?? 'div'; + const Root = slots.root ?? component ?? 'div'; const rootProps: WithOptionalOwnerState = useSlotProps({ elementType: Root, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, additionalProps: { ref }, ownerState, }); - const FirstButton = components.FirstButton ?? 'button'; + const FirstButton = slots.firstButton ?? 'button'; const firstButtonProps: WithOptionalOwnerState = useSlotProps({ elementType: FirstButton, - externalSlotProps: componentsProps.firstButton, + externalSlotProps: slotProps.firstButton, additionalProps: { onClick: handleFirstPageButtonClick, disabled: page === 0, @@ -92,11 +92,11 @@ const TablePaginationActionsUnstyled = React.forwardRef< ownerState, }); - const LastButton = components.LastButton ?? 'button'; + const LastButton = slots.lastButton ?? 'button'; const lastButtonProps: WithOptionalOwnerState = useSlotProps({ elementType: LastButton, - externalSlotProps: componentsProps.lastButton, + externalSlotProps: slotProps.lastButton, additionalProps: { onClick: handleLastPageButtonClick, disabled: page >= Math.ceil(count / rowsPerPage) - 1, @@ -106,11 +106,11 @@ const TablePaginationActionsUnstyled = React.forwardRef< ownerState, }); - const NextButton = components.NextButton ?? 'button'; + const NextButton = slots.nextButton ?? 'button'; const nextButtonProps: WithOptionalOwnerState = useSlotProps({ elementType: NextButton, - externalSlotProps: componentsProps.nextButton, + externalSlotProps: slotProps.nextButton, additionalProps: { onClick: handleNextButtonClick, disabled: count !== -1 ? page >= Math.ceil(count / rowsPerPage) - 1 : false, @@ -120,11 +120,11 @@ const TablePaginationActionsUnstyled = React.forwardRef< ownerState, }); - const BackButton = components.BackButton ?? 'button'; + const BackButton = slots.backButton ?? 'button'; const backButtonProps: WithOptionalOwnerState = useSlotProps({ elementType: BackButton, - externalSlotProps: componentsProps.backButton, + externalSlotProps: slotProps.backButton, additionalProps: { onClick: handleBackButtonClick, disabled: page === 0, @@ -134,10 +134,10 @@ const TablePaginationActionsUnstyled = React.forwardRef< ownerState, }); - const LastPageIcon = components.LastPageIcon ?? LastPageIconDefault; - const FirstPageIcon = components.FirstPageIcon ?? FirstPageIconDefault; - const NextPageIcon = components.NextPageIcon ?? NextPageIconDefault; - const BackPageIcon = components.BackPageIcon ?? BackPageIconDefault; + const LastPageIcon = slots.lastPageIcon ?? LastPageIconDefault; + const FirstPageIcon = slots.firstPageIcon ?? FirstPageIconDefault; + const NextPageIcon = slots.nextPageIcon ?? NextPageIconDefault; + const BackPageIcon = slots.backPageIcon ?? BackPageIconDefault; return ( diff --git a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationActionsUnstyled.types.ts b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationActionsUnstyled.types.ts index 0eaea70533d91a..38f13381f8aa16 100644 --- a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationActionsUnstyled.types.ts +++ b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationActionsUnstyled.types.ts @@ -15,22 +15,22 @@ export interface TablePaginationActionsUnstyledOwnProps { * Either a string to use a HTML element or a component. * @default {} */ - components?: { - Root?: React.ElementType; - FirstButton?: React.ElementType; - LastButton?: React.ElementType; - NextButton?: React.ElementType; - BackButton?: React.ElementType; - FirstPageIcon?: React.ElementType; - LastPageIcon?: React.ElementType; - NextPageIcon?: React.ElementType; - BackPageIcon?: React.ElementType; + slots?: { + root?: React.ElementType; + firstButton?: React.ElementType; + lastButton?: React.ElementType; + nextButton?: React.ElementType; + backButton?: React.ElementType; + firstPageIcon?: React.ElementType; + lastPageIcon?: React.ElementType; + nextPageIcon?: React.ElementType; + backPageIcon?: React.ElementType; }; /** * The props used for each slot inside the TablePagination. * @default {} */ - componentsProps?: { + slotProps?: { root?: SlotComponentProps< 'div', TablePaginationActionsUnstyledComponentsPropsOverrides, diff --git a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.spec.tsx b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.spec.tsx index b22e8202b186c6..15c9d257cd64d1 100644 --- a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.spec.tsx +++ b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.spec.tsx @@ -57,6 +57,15 @@ const styledTablePagination = ( onPageChange={() => {}} page={0} rowsPerPage={10} - components={{ Root, Actions, Select, MenuItem, SelectLabel, DisplayedRows, Toolbar, Spacer }} + slots={{ + root: Root, + actions: Actions, + select: Select, + menuItem: MenuItem, + selectLabel: SelectLabel, + displayedRows: DisplayedRows, + toolbar: Toolbar, + spacer: Spacer, + }} /> ); diff --git a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.test.tsx b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.test.tsx index f67e7fa92dfe8e..ae9a6351ce18d2 100644 --- a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.test.tsx +++ b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.test.tsx @@ -307,7 +307,7 @@ describe('', () => { onPageChange={(_, newPage) => { setPage(newPage); }} - componentsProps={{ + slotProps={{ displayedRows: { 'data-testid': 'displayedRows', } as any, @@ -339,7 +339,7 @@ describe('', () => { rowsPerPage={10} count={98} onPageChange={handleChangePage} - componentsProps={{ + slotProps={{ actions: { showFirstButton: true, } as any, @@ -367,7 +367,7 @@ describe('', () => { rowsPerPage={10} count={98} onPageChange={handleChangePage} - componentsProps={{ + slotProps={{ actions: { showLastButton: true, } as any, @@ -470,7 +470,7 @@ describe('', () => { rowsPerPage={10} page={0} onPageChange={noop} - componentsProps={{ + slotProps={{ select: { 'aria-label': 'rows per page' }, }} /> diff --git a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.tsx b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.tsx index a54ff2c373c2dd..5315aa9919dffb 100644 --- a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.tsx +++ b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.tsx @@ -62,8 +62,6 @@ const TablePaginationUnstyled = React.forwardRef = useSlotProps({ elementType: Root, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, additionalProps: { colSpan, @@ -110,11 +110,11 @@ const TablePaginationUnstyled = React.forwardRef = useSlotProps({ elementType: Select, - externalSlotProps: componentsProps.select, + externalSlotProps: slotProps.select, additionalProps: { value: rowsPerPage, id: selectId, @@ -127,11 +127,11 @@ const TablePaginationUnstyled = React.forwardRef = useSlotProps({ elementType: Actions, - externalSlotProps: componentsProps.actions, + externalSlotProps: slotProps.actions, additionalProps: { page, rowsPerPage, @@ -143,11 +143,11 @@ const TablePaginationUnstyled = React.forwardRef = useSlotProps({ elementType: MenuItem, - externalSlotProps: componentsProps.menuItem, + externalSlotProps: slotProps.menuItem, additionalProps: { value: undefined, }, @@ -155,11 +155,11 @@ const TablePaginationUnstyled = React.forwardRef = useSlotProps({ elementType: SelectLabel, - externalSlotProps: componentsProps.selectLabel, + externalSlotProps: slotProps.selectLabel, additionalProps: { id: labelId, }, @@ -167,29 +167,29 @@ const TablePaginationUnstyled = React.forwardRef = useSlotProps({ elementType: DisplayedRows, - externalSlotProps: componentsProps.displayedRows, + externalSlotProps: slotProps.displayedRows, ownerState, className: classes.displayedRows, }); - const Toolbar = components.Toolbar ?? 'div'; + const Toolbar = slots.toolbar ?? 'div'; const toolbarProps: WithOptionalOwnerState = useSlotProps({ elementType: Toolbar, - externalSlotProps: componentsProps.toolbar, + externalSlotProps: slotProps.toolbar, ownerState, className: classes.toolbar, }); - const Spacer = components.Spacer ?? 'div'; + const Spacer = slots.spacer ?? 'div'; const spacerProps: WithOptionalOwnerState = useSlotProps({ elementType: Spacer, - externalSlotProps: componentsProps.spacer, + externalSlotProps: slotProps.spacer, ownerState, className: classes.spacer, }); @@ -261,35 +261,6 @@ TablePaginationUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the TablePagination. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Actions: PropTypes.elementType, - DisplayedRows: PropTypes.elementType, - MenuItem: PropTypes.elementType, - Root: PropTypes.elementType, - Select: PropTypes.elementType, - SelectLabel: PropTypes.elementType, - Spacer: PropTypes.elementType, - Toolbar: PropTypes.elementType, - }), - /** - * The props used for each slot inside the TablePagination. - * @default {} - */ - componentsProps: PropTypes.shape({ - actions: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - displayedRows: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - menuItem: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - select: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - selectLabel: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - spacer: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - toolbar: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * The total number of rows. * @@ -386,6 +357,35 @@ TablePaginationUnstyled.propTypes /* remove-proptypes */ = { * Id of the select element within the pagination. */ selectId: PropTypes.string, + /** + * The props used for each slot inside the TablePagination. + * @default {} + */ + slotProps: PropTypes.shape({ + actions: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + displayedRows: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + menuItem: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + select: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + selectLabel: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + spacer: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + toolbar: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the TablePagination. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + actions: PropTypes.elementType, + displayedRows: PropTypes.elementType, + menuItem: PropTypes.elementType, + root: PropTypes.elementType, + select: PropTypes.elementType, + selectLabel: PropTypes.elementType, + spacer: PropTypes.elementType, + toolbar: PropTypes.elementType, + }), } as any; export default TablePaginationUnstyled; diff --git a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.types.ts b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.types.ts index e14c26a3dd8f0d..86649ea618ff78 100644 --- a/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.types.ts +++ b/packages/mui-base/src/TablePaginationUnstyled/TablePaginationUnstyled.types.ts @@ -28,21 +28,21 @@ export interface TablePaginationUnstyledOwnProps { * Either a string to use a HTML element or a component. * @default {} */ - components?: { - Root?: React.ElementType; - Actions?: React.ElementType; - Select?: React.ElementType; - SelectLabel?: React.ElementType; - MenuItem?: React.ElementType; - DisplayedRows?: React.ElementType; - Toolbar?: React.ElementType; - Spacer?: React.ElementType; + slots?: { + root?: React.ElementType; + actions?: React.ElementType; + select?: React.ElementType; + selectLabel?: React.ElementType; + menuItem?: React.ElementType; + displayedRows?: React.ElementType; + toolbar?: React.ElementType; + spacer?: React.ElementType; }; /** * The props used for each slot inside the TablePagination. * @default {} */ - componentsProps?: { + slotProps?: { root?: SlotComponentProps< 'div', TablePaginationUnstyledComponentsPropsOverrides, diff --git a/packages/mui-base/src/TabsListUnstyled/TabsListUnstyled.spec.tsx b/packages/mui-base/src/TabsListUnstyled/TabsListUnstyled.spec.tsx index 19b3246e12c13a..c9157170af5b65 100644 --- a/packages/mui-base/src/TabsListUnstyled/TabsListUnstyled.spec.tsx +++ b/packages/mui-base/src/TabsListUnstyled/TabsListUnstyled.spec.tsx @@ -7,7 +7,7 @@ function Root(props: TabsListUnstyledRootSlotProps) { return
    ; } -const styledTabsList = ; +const styledTabsList = ; const polymorphicComponentTest = () => { const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> = () =>
    ; diff --git a/packages/mui-base/src/TabsListUnstyled/TabsListUnstyled.tsx b/packages/mui-base/src/TabsListUnstyled/TabsListUnstyled.tsx index 1ec23620c402f2..8dd983feb0ad70 100644 --- a/packages/mui-base/src/TabsListUnstyled/TabsListUnstyled.tsx +++ b/packages/mui-base/src/TabsListUnstyled/TabsListUnstyled.tsx @@ -32,7 +32,7 @@ const useUtilityClasses = (ownerState: { orientation: 'horizontal' | 'vertical' * - [TabsListUnstyled API](https://mui.com/base/api/tabs-list-unstyled/) */ const TabsListUnstyled = React.forwardRef((props, ref) => { - const { children, component, components = {}, componentsProps = {}, ...other } = props; + const { children, component, slotProps = {}, slots = {}, ...other } = props; const { isRtl, orientation, getRootProps, processChildren } = useTabsList({ ...props, ref }); @@ -44,11 +44,11 @@ const TabsListUnstyled = React.forwardRef((props const classes = useUtilityClasses(ownerState); - const TabsListRoot: React.ElementType = component ?? components.Root ?? 'div'; + const TabsListRoot: React.ElementType = component ?? slots.root ?? 'div'; const tabsListRootProps: WithOptionalOwnerState = useSlotProps({ elementType: TabsListRoot, getSlotProps: getRootProps, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, ownerState, className: classes.root, @@ -74,19 +74,19 @@ TabsListUnstyled.propTypes /* remove-proptypes */ = { */ component: PropTypes.elementType, /** - * The components used for each slot inside the TabsList. - * Either a string to use a HTML element or a component. + * The props used for each slot inside the TabsList. * @default {} */ - components: PropTypes.shape({ - Root: PropTypes.elementType, + slotProps: PropTypes.shape({ + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), }), /** - * The props used for each slot inside the TabsList. + * The components used for each slot inside the TabsList. + * Either a string to use a HTML element or a component. * @default {} */ - componentsProps: PropTypes.shape({ - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + slots: PropTypes.shape({ + root: PropTypes.elementType, }), } as any; diff --git a/packages/mui-base/src/TabsListUnstyled/TabsListUnstyled.types.ts b/packages/mui-base/src/TabsListUnstyled/TabsListUnstyled.types.ts index 4dbf1edc77349c..beb53a28d7716b 100644 --- a/packages/mui-base/src/TabsListUnstyled/TabsListUnstyled.types.ts +++ b/packages/mui-base/src/TabsListUnstyled/TabsListUnstyled.types.ts @@ -11,25 +11,25 @@ export interface TabsListUnstyledOwnProps { */ children?: React.ReactNode; className?: string; - /** - * The components used for each slot inside the TabsList. - * Either a string to use a HTML element or a component. - * @default {} - */ - components?: { - Root?: React.ElementType; - }; /** * The props used for each slot inside the TabsList. * @default {} */ - componentsProps?: { + slotProps?: { root?: SlotComponentProps< 'div', TabsListUnstyledComponentsPropsOverrides, TabsListUnstyledOwnerState >; }; + /** + * The components used for each slot inside the TabsList. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots?: { + root?: React.ElementType; + }; } export interface TabsListUnstyledTypeMap

    { diff --git a/packages/mui-base/src/TabsUnstyled/TabsUnstyled.spec.tsx b/packages/mui-base/src/TabsUnstyled/TabsUnstyled.spec.tsx index eb706aef2671cd..b8b9de99bd9e5a 100644 --- a/packages/mui-base/src/TabsUnstyled/TabsUnstyled.spec.tsx +++ b/packages/mui-base/src/TabsUnstyled/TabsUnstyled.spec.tsx @@ -7,7 +7,7 @@ function Root(props: TabsUnstyledRootSlotProps) { return

    ; } -const styledTabs = ; +const styledTabs = ; const polymorphicComponentTest = () => { const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> = () =>
    ; diff --git a/packages/mui-base/src/TabsUnstyled/TabsUnstyled.tsx b/packages/mui-base/src/TabsUnstyled/TabsUnstyled.tsx index 883a208f3d24ed..7d2636e3b3118c 100644 --- a/packages/mui-base/src/TabsUnstyled/TabsUnstyled.tsx +++ b/packages/mui-base/src/TabsUnstyled/TabsUnstyled.tsx @@ -40,10 +40,10 @@ const TabsUnstyled = React.forwardRef((props, ref) = orientation = 'horizontal', direction = 'ltr', component, - components = {}, - componentsProps = {}, onChange, selectionFollowsFocus, + slotProps = {}, + slots = {}, ...other } = props; @@ -57,10 +57,10 @@ const TabsUnstyled = React.forwardRef((props, ref) = const classes = useUtilityClasses(ownerState); - const TabsRoot: React.ElementType = component ?? components.Root ?? 'div'; + const TabsRoot: React.ElementType = component ?? slots.root ?? 'div'; const tabsRootProps: WithOptionalOwnerState = useSlotProps({ elementType: TabsRoot, - externalSlotProps: componentsProps.root, + externalSlotProps: slotProps.root, externalForwardedProps: other, additionalProps: { ref, @@ -90,21 +90,6 @@ TabsUnstyled.propTypes /* remove-proptypes */ = { * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, - /** - * The components used for each slot inside the Tabs. - * Either a string to use a HTML element or a component. - * @default {} - */ - components: PropTypes.shape({ - Root: PropTypes.elementType, - }), - /** - * The props used for each slot inside the Tabs. - * @default {} - */ - componentsProps: PropTypes.shape({ - root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - }), /** * The default value. Use when the component is not controlled. */ @@ -128,6 +113,21 @@ TabsUnstyled.propTypes /* remove-proptypes */ = { * changes on activation. */ selectionFollowsFocus: PropTypes.bool, + /** + * The props used for each slot inside the Tabs. + * @default {} + */ + slotProps: PropTypes.shape({ + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the Tabs. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + root: PropTypes.elementType, + }), /** * The value of the currently selected `Tab`. * If you don't want any selected `Tab`, you can set this prop to `false`. diff --git a/packages/mui-base/src/TabsUnstyled/TabsUnstyled.types.ts b/packages/mui-base/src/TabsUnstyled/TabsUnstyled.types.ts index 0ff284f330d6c7..449149789b12f6 100644 --- a/packages/mui-base/src/TabsUnstyled/TabsUnstyled.types.ts +++ b/packages/mui-base/src/TabsUnstyled/TabsUnstyled.types.ts @@ -34,29 +34,29 @@ export interface TabsUnstyledOwnProps { direction?: TabsUnstyledDirection; className?: string; /** - * The components used for each slot inside the Tabs. - * Either a string to use a HTML element or a component. - * @default {} + * Callback invoked when new value is being set. */ - components?: { - Root?: React.ElementType; - }; + onChange?: (event: React.SyntheticEvent, value: number | string | boolean) => void; + /** + * If `true` the selected tab changes on focus. Otherwise it only + * changes on activation. + */ + selectionFollowsFocus?: boolean; /** * The props used for each slot inside the Tabs. * @default {} */ - componentsProps?: { + slotProps?: { root?: SlotComponentProps<'div', TabsUnstyledComponentsPropsOverrides, TabsUnstyledOwnerState>; }; /** - * Callback invoked when new value is being set. - */ - onChange?: (event: React.SyntheticEvent, value: number | string | boolean) => void; - /** - * If `true` the selected tab changes on focus. Otherwise it only - * changes on activation. + * The components used for each slot inside the Tabs. + * Either a string to use a HTML element or a component. + * @default {} */ - selectionFollowsFocus?: boolean; + slots?: { + root?: React.ElementType; + }; } export interface TabsUnstyledTypeMap

    { diff --git a/packages/mui-base/src/utils/mergeSlotProps.ts b/packages/mui-base/src/utils/mergeSlotProps.ts index e9ac631f759e4e..c7e9ea0d3a1e87 100644 --- a/packages/mui-base/src/utils/mergeSlotProps.ts +++ b/packages/mui-base/src/utils/mergeSlotProps.ts @@ -23,7 +23,7 @@ export interface MergeSlotPropsParameters< */ getSlotProps?: (other: EventHandlers) => WithCommonProps; /** - * Props provided to the `componentsProps.*` of the unstyled component. + * Props provided to the `slotProps.*` of the unstyled component. */ externalSlotProps?: WithCommonProps; /** @@ -64,7 +64,7 @@ export type MergeSlotPropsResult< * 1. The internal props (specified as a getter function to work with get*Props hook result) * 2. Additional props (specified internally on an unstyled component) * 3. External props specified on the owner component. These should only be used on a root slot. - * 4. External props specified in the `componentsProps.*` prop. + * 4. External props specified in the `slotProps.*` prop. * 5. The `className` prop - combined from all the above. * @param parameters * @returns diff --git a/packages/mui-base/src/utils/useSlotProps.test.tsx b/packages/mui-base/src/utils/useSlotProps.test.tsx index 2a769d2bc94348..3d0fce22f9614f 100644 --- a/packages/mui-base/src/utils/useSlotProps.test.tsx +++ b/packages/mui-base/src/utils/useSlotProps.test.tsx @@ -188,7 +188,7 @@ describe('useSlotProps', () => { onClick: externalForwardedClickHandler, }; - // provided by the user via componentsProps.*: + // provided by the user via slotProps.*: const componentProps = (os: typeof ownerState) => ({ 'data-fromownerstate': os.test, 'data-test': 'externalComponentsProps', @@ -222,7 +222,7 @@ describe('useSlotProps', () => { // `id` from componentProps overrides the one from getSlotProps expect(result).to.haveOwnProperty('id', 'external'); - // `componentsProps` is called with the ownerState + // `slotProps` is called with the ownerState expect(result).to.haveOwnProperty('data-fromownerstate', true); // class names are concatenated @@ -240,17 +240,17 @@ describe('useSlotProps', () => { expect(externalRef.current).to.equal('test'); expect(additionalRef.current).to.equal('test'); - // event handler provided in componentsProps is called + // event handler provided in slotProps is called result.onClick({} as React.MouseEvent); expect(externalClickHandler.calledOnce).to.equal(true); - // event handler provided in forwardedProps is not called (was overridden by componentsProps) + // event handler provided in forwardedProps is not called (was overridden by slotProps) expect(externalForwardedClickHandler.notCalled).to.equal(true); // internal event handler is called expect(internalClickHandler.calledOnce).to.equal(true); - // internal ownerState is merged with the one provided by componentsProps + // internal ownerState is merged with the one provided by slotProps expect(result.ownerState).to.deep.equal({ test: true, foo: 'bar', diff --git a/packages/mui-base/src/utils/useSlotProps.ts b/packages/mui-base/src/utils/useSlotProps.ts index a644e00565bf30..9fae5f82c75954 100644 --- a/packages/mui-base/src/utils/useSlotProps.ts +++ b/packages/mui-base/src/utils/useSlotProps.ts @@ -24,7 +24,7 @@ export type UseSlotPropsParameters< */ elementType: ElementType; /** - * The `componentsProps.*` of the unstyled component. + * The `slotProps.*` of the unstyled component. */ externalSlotProps: | ExternalSlotProps diff --git a/packages/mui-base/test/integration/SelectUnstyled.test.tsx b/packages/mui-base/test/integration/SelectUnstyled.test.tsx index f4ed224e98423c..3480e04462c295 100644 --- a/packages/mui-base/test/integration/SelectUnstyled.test.tsx +++ b/packages/mui-base/test/integration/SelectUnstyled.test.tsx @@ -25,16 +25,12 @@ describe(' integration', () => { ref: React.Ref, ) { return ( - + ); }); const { getByRole } = render( - + diff --git a/packages/mui-base/test/typescript/moduleAugmentation/selectUnstyledComponentsProps.spec.tsx b/packages/mui-base/test/typescript/moduleAugmentation/selectUnstyledComponentsProps.spec.tsx index 3278613b06f654..d95dfca359da71 100644 --- a/packages/mui-base/test/typescript/moduleAugmentation/selectUnstyledComponentsProps.spec.tsx +++ b/packages/mui-base/test/typescript/moduleAugmentation/selectUnstyledComponentsProps.spec.tsx @@ -11,12 +11,12 @@ declare module '@mui/base' { } } -; +; // @ts-expect-error unknown variant -; +; -; +; // @ts-expect-error unknown variant -; +; diff --git a/packages/mui-base/test/typescript/moduleAugmentation/sliderComponentsProps.spec.tsx b/packages/mui-base/test/typescript/moduleAugmentation/sliderComponentsProps.spec.tsx index d4ef0b1dc79ba4..07906203a55bd9 100644 --- a/packages/mui-base/test/typescript/moduleAugmentation/sliderComponentsProps.spec.tsx +++ b/packages/mui-base/test/typescript/moduleAugmentation/sliderComponentsProps.spec.tsx @@ -7,7 +7,7 @@ declare module '@mui/base' { } } -; +; // @ts-expect-error unknown color -; +; diff --git a/packages/mui-codemod/README.md b/packages/mui-codemod/README.md index c91800a0e2b46b..81c45a70a61e1e 100644 --- a/packages/mui-codemod/README.md +++ b/packages/mui-codemod/README.md @@ -237,6 +237,30 @@ npx @mui/codemod v5.0.0/badge-overlap-value You can find more details about this breaking change in [the migration guide](https://mui.com/material-ui/migration/v5-component-changes/#badge). +#### `base-rename-components-to-slots` + +Renames the `components` and `componentsProps` props to `slots` and `slotProps`, respectively. +Also, changes `slots`' fields names to camelCase. + +This change only affects MUI Base components. + +```diff + ; +``` + + + +```sh +npx @mui/codemod v5.0.0/base-rename-components-to-slots +``` + +The associated breaking change was done in [#34693](https://github.com/mui/material-ui/pull/34693). + #### `box-borderradius-values` Updates the Box API from separate system props to `sx`. diff --git a/packages/mui-codemod/src/v5.0.0/base-rename-components-to-slots.js b/packages/mui-codemod/src/v5.0.0/base-rename-components-to-slots.js new file mode 100644 index 00000000000000..240310d589b038 --- /dev/null +++ b/packages/mui-codemod/src/v5.0.0/base-rename-components-to-slots.js @@ -0,0 +1,57 @@ +function transformComponentsProp(attributeNode) { + attributeNode.name.name = 'slots'; + + const valueExpression = attributeNode.value.expression; + if (valueExpression?.type !== 'ObjectExpression') { + return; + } + + valueExpression.properties.forEach((property) => { + property.key.name = property.key.name[0].toLowerCase() + property.key.name.slice(1); + + if (property.shorthand) { + property.shorthand = false; + } + }); +} + +function transformComponentsPropsProp(attributeNode) { + attributeNode.name.name = 'slotProps'; +} + +/** + * @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; + + const transformed = root.findJSXElements().forEach((path) => { + // Process only unstyled components + if (!path.node.openingElement.name.name.endsWith('Unstyled')) { + return; + } + + path.node.openingElement.attributes.forEach((node) => { + if (node.type !== 'JSXAttribute') { + return; + } + + switch (node.name.name) { + case 'components': + transformComponentsProp(node); + break; + + case 'componentsProps': + transformComponentsPropsProp(node); + break; + + default: + } + }); + }); + + return transformed.toSource(printOptions); +} diff --git a/packages/mui-codemod/src/v5.0.0/base-rename-components-to-slots.test.js b/packages/mui-codemod/src/v5.0.0/base-rename-components-to-slots.test.js new file mode 100644 index 00000000000000..b5c64b84953a96 --- /dev/null +++ b/packages/mui-codemod/src/v5.0.0/base-rename-components-to-slots.test.js @@ -0,0 +1,29 @@ +import path from 'path'; +import { expect } from 'chai'; +import jscodeshift from 'jscodeshift'; +import transform from './base-rename-components-to-slots'; +import readFile from '../util/readFile'; + +function read(fileName) { + return readFile(path.join(__dirname, fileName)); +} + +describe('@mui/codemod', () => { + describe('v5.0.0', () => { + describe('base-rename-components-to-slots', () => { + it('transforms props as needed', () => { + const actual = transform( + { + source: read('./base-rename-components-to-slots.test/actual.js'), + path: require.resolve('./base-rename-components-to-slots.test/actual.js'), + }, + { jscodeshift }, + {}, + ); + + const expected = read('./base-rename-components-to-slots.test/expected.js'); + expect(actual).to.equal(expected, 'The transformed version should be correct'); + }); + }); + }); +}); diff --git a/packages/mui-codemod/src/v5.0.0/base-rename-components-to-slots.test/actual.js b/packages/mui-codemod/src/v5.0.0/base-rename-components-to-slots.test/actual.js new file mode 100644 index 00000000000000..41d9632be8e368 --- /dev/null +++ b/packages/mui-codemod/src/v5.0.0/base-rename-components-to-slots.test/actual.js @@ -0,0 +1,14 @@ +; + +; + +; diff --git a/packages/mui-codemod/src/v5.0.0/base-rename-components-to-slots.test/expected.js b/packages/mui-codemod/src/v5.0.0/base-rename-components-to-slots.test/expected.js new file mode 100644 index 00000000000000..be2702b3922962 --- /dev/null +++ b/packages/mui-codemod/src/v5.0.0/base-rename-components-to-slots.test/expected.js @@ -0,0 +1,14 @@ +; + +; + +; diff --git a/packages/mui-material-next/src/Input/Input.d.ts b/packages/mui-material-next/src/Input/Input.d.ts index 649fd5812f9636..30dea079c16f44 100644 --- a/packages/mui-material-next/src/Input/Input.d.ts +++ b/packages/mui-material-next/src/Input/Input.d.ts @@ -50,6 +50,7 @@ export interface InputOwnProps { components?: { Root?: React.ElementType; Input?: React.ElementType; + Textarea?: React.ElementType; }; /** * The props used for each slot inside the Input. @@ -58,6 +59,7 @@ export interface InputOwnProps { componentsProps?: { root?: React.HTMLAttributes & InputComponentsPropsOverrides; input?: React.InputHTMLAttributes & InputComponentsPropsOverrides; + textarea?: React.TextareaHTMLAttributes & InputComponentsPropsOverrides; }; /** * The default value. Use when the component is not controlled. @@ -161,6 +163,25 @@ export interface InputOwnProps { * The size of the component. */ size?: OverridableStringUnion<'small' | 'medium', InputBasePropsSizeOverrides>; + /** + * The props used for each slot inside the Input. + * @default {} + */ + slotProps?: { + root?: React.HTMLAttributes & InputComponentsPropsOverrides; + input?: React.InputHTMLAttributes & InputComponentsPropsOverrides; + textarea?: React.TextareaHTMLAttributes & InputComponentsPropsOverrides; + }; + /** + * The components used for each slot inside the Input. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots?: { + root?: React.ElementType; + input?: React.ElementType; + textarea?: React.ElementType; + }; /** * Start `InputAdornment` for this component. */ diff --git a/packages/mui-material-next/src/Input/Input.js b/packages/mui-material-next/src/Input/Input.js index 46842d8f13c95b..f6d990c45b9c07 100644 --- a/packages/mui-material-next/src/Input/Input.js +++ b/packages/mui-material-next/src/Input/Input.js @@ -270,16 +270,22 @@ const Input = React.forwardRef(function Input(inProps, ref) { fullWidth = false, hiddenLabel = false, size, + slotProps, + slots, startAdornment, ...other } = props; const components = { - Root: component ?? componentsProp.Root ?? InputRoot, - Input: componentsProp.Input ?? InputInput, - Textarea: componentsProp.Textarea ?? InputTextarea, + root: component ?? slots?.root ?? componentsProp.Root ?? InputRoot, + input: slots?.input ?? componentsProp.Input ?? InputInput, + textarea: slots?.textarea ?? componentsProp.Textarea ?? InputTextarea, }; + const rootSlotProps = slotProps?.root ?? componentsProps.root; + const inputSlotProps = slotProps?.input ?? componentsProps.input; + const textareaSlotProps = slotProps?.textarea ?? componentsProps.textarea; + const ownerState = { ...props, color: 'primary', @@ -293,19 +299,27 @@ const Input = React.forwardRef(function Input(inProps, ref) { const amendedComponentsProps = { root: appendOwnerState( - components.Root, + components.root, { - ...componentsProps.root, - className: clsx(classes.root, className, componentsProps.root?.className), + ...rootSlotProps, + className: clsx(classes.root, className, rootSlotProps?.className), }, ownerState, ), input: appendOwnerState( - components.Input, + components.input, { type: 'text', - ...componentsProps.input, - className: clsx(classes.input, componentsProps.input?.className), + ...inputSlotProps, + className: clsx(classes.input, inputSlotProps?.className), + }, + ownerState, + ), + textarea: appendOwnerState( + components.textarea, + { + ...textareaSlotProps, + className: textareaSlotProps?.className, }, ownerState, ), @@ -317,8 +331,8 @@ const Input = React.forwardRef(function Input(inProps, ref) { endAdornment={endAdornment} {...other} ref={ref} - components={components} - componentsProps={amendedComponentsProps} + slots={components} + slotProps={amendedComponentsProps} /> ); }); @@ -375,6 +389,7 @@ Input.propTypes /* remove-proptypes */ = { components: PropTypes.shape({ Input: PropTypes.elementType, Root: PropTypes.elementType, + Textarea: PropTypes.elementType, }), /** * The props used for each slot inside the Input. @@ -383,6 +398,7 @@ Input.propTypes /* remove-proptypes */ = { componentsProps: PropTypes.shape({ input: PropTypes.object, root: PropTypes.object, + textarea: PropTypes.object, }), /** * The default value. Use when the component is not controlled. @@ -494,6 +510,25 @@ Input.propTypes /* remove-proptypes */ = { * The size of the component. */ size: PropTypes.oneOf(['small', 'medium']), + /** + * The props used for each slot inside the Input. + * @default {} + */ + slotProps: PropTypes.shape({ + input: PropTypes.object, + root: PropTypes.object, + textarea: PropTypes.object, + }), + /** + * The components used for each slot inside the Input. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + input: PropTypes.elementType, + root: PropTypes.elementType, + textarea: PropTypes.elementType, + }), /** * Start `InputAdornment` for this component. */ diff --git a/packages/mui-material-next/src/Input/Input.test.js b/packages/mui-material-next/src/Input/Input.test.js index 6a5ec582f078ca..8eeb3c60bd27cb 100644 --- a/packages/mui-material-next/src/Input/Input.test.js +++ b/packages/mui-material-next/src/Input/Input.test.js @@ -157,7 +157,7 @@ describe('', () => { return ; }); - render(); + render(); expect(typeof injectedProps.onBlur).to.equal('function'); expect(typeof injectedProps.onFocus).to.equal('function'); @@ -188,32 +188,32 @@ describe('', () => { const triggerChangeRef = React.createRef(); const inputProps = { - componentsProps: { + slotProps: { input: { ref: triggerChangeRef, }, }, }; - /* render(); + /* render(); expect(true).to.equal(true); */ expect(() => { - render(); + render(); }).toErrorDev([ - 'MUI: You have provided a `components.Input` to the input component\nthat does not correctly handle the `ref` prop.\nMake sure the `ref` prop is called with a HTMLInputElement.', + 'MUI: You have provided a `slots.input` to the input component\nthat does not correctly handle the `ref` prop.\nMake sure the `ref` prop is called with a HTMLInputElement.', // React 18 Strict Effects run mount effects twice React.version.startsWith('18') && - 'MUI: You have provided a `components.Input` to the input component\nthat does not correctly handle the `ref` prop.\nMake sure the `ref` prop is called with a HTMLInputElement.', + 'MUI: You have provided a `slots.input` to the input component\nthat does not correctly handle the `ref` prop.\nMake sure the `ref` prop is called with a HTMLInputElement.', ]); }); }); }); - describe('prop: componentsProps', () => { + describe('prop: slotProps', () => { it('should apply the props on the input', () => { const inputProps = { - componentsProps: { + slotProps: { input: { className: 'foo', maxLength: 5, @@ -230,7 +230,7 @@ describe('', () => { it('should be able to get a ref', () => { const inputRef = React.createRef(); const inputProps = { - componentsProps: { + slotProps: { input: { ref: inputRef, }, @@ -242,7 +242,7 @@ describe('', () => { }); }); - describe('prop: components and componentsProps', () => { + describe('prop: slots and slotProps', () => { it('should call onChange inputProp callback with all params sent from custom input slot', () => { const INPUT_VALUE = 'material'; const OUTPUT_VALUE = 'test'; @@ -267,14 +267,14 @@ describe('', () => { } const inputProps = { - componentsProps: { + slotProps: { input: { onChange: parentHandleChange, }, }, }; - const { getByRole } = render(); + const { getByRole } = render(); const textbox = getByRole('textbox'); fireEvent.change(textbox, { target: { value: INPUT_VALUE } }); @@ -306,7 +306,7 @@ describe('', () => { it('should be able to access the native input', () => { const inputRef = React.createRef(); const inputProps = { - componentsProps: { + slotProps: { input: { ref: inputRef, }, @@ -319,7 +319,7 @@ describe('', () => { it('should be able to access the native textarea', () => { const inputRef = React.createRef(); const inputProps = { - componentsProps: { + slotProps: { input: { ref: inputRef, }, diff --git a/packages/mui-material-next/src/TablePagination/TablePagination.js b/packages/mui-material-next/src/TablePagination/TablePagination.js index a8a4b70ccb68ed..6efc45e7de87b6 100644 --- a/packages/mui-material-next/src/TablePagination/TablePagination.js +++ b/packages/mui-material-next/src/TablePagination/TablePagination.js @@ -171,33 +171,33 @@ const TablePagination = React.forwardRef(function TablePagination(inProps, ref) return ( ; + /** + * The props used for each slot inside the Badge. + * @default {} + */ + componentsProps?: BadgeUnstyledTypeMap['props']['slotProps']; + /** + * The components used for each slot inside the Badge. + * Either a string to use a HTML element or a component. + * @default {} + */ + components?: { + Root?: React.ElementType; + Badge?: React.ElementType; + }; /** * Wrapped shape the badge should overlap. * @default 'rectangular' @@ -64,8 +78,8 @@ export type BadgeTypeMap< defaultComponent: D; }>; -type BadgeRootProps = NonNullable['root']; -type BadgeBadgeProps = NonNullable['badge']; +type BadgeRootProps = NonNullable['root']; +type BadgeBadgeProps = NonNullable['badge']; export declare const BadgeRoot: React.FC; export declare const BadgeMark: React.FC; diff --git a/packages/mui-material/src/Badge/Badge.js b/packages/mui-material/src/Badge/Badge.js index 731c7a5af48a77..73c48dce3ca348 100644 --- a/packages/mui-material/src/Badge/Badge.js +++ b/packages/mui-material/src/Badge/Badge.js @@ -208,6 +208,8 @@ const Badge = React.forwardRef(function Badge(inProps, ref) { invisible: invisibleProp = false, max, badgeContent: badgeContentProp, + slots, + slotProps, showZero = false, variant: variantProp = 'standard', ...other @@ -246,6 +248,13 @@ const Badge = React.forwardRef(function Badge(inProps, ref) { badgeContentProp && Number(badgeContentProp) > max ? `${max}+` : badgeContentProp; } + // support both `slots` and `components` for backward compatibility + const RootSlot = slots?.root ?? components.Root ?? BadgeRoot; + const BadgeSlot = slots?.badge ?? components.Badge ?? BadgeBadge; + + const rootSlotProps = slotProps?.root ?? componentsProps.root; + const badgeSlotProps = slotProps?.badge ?? componentsProps.badge; + return ( ', () => { }); }); + describe('prop: components / slots', () => { + it('allows overriding the slots using the components prop', () => { + const CustomRoot = React.forwardRef((props, ref) => { + const { ownerState, ...other } = props; + return ; + }); + + const CustomBadge = React.forwardRef((props, ref) => { + const { ownerState, ...other } = props; + return ; + }); + + const { getByTestId } = render( + , + ); + + getByTestId('custom-root'); + getByTestId('custom-badge'); + }); + + it('allows overriding the slots using the slots prop', () => { + const CustomRoot = React.forwardRef((props, ref) => { + const { ownerState, ...other } = props; + return ; + }); + + const CustomBadge = React.forwardRef((props, ref) => { + const { ownerState, ...other } = props; + return ; + }); + + const { getByTestId } = render( + , + ); + + getByTestId('custom-root'); + getByTestId('custom-badge'); + }); + }); + + describe('prop: componentsProps / slotProps', () => { + it('allows modifying slots props using the componentsProps prop', () => { + const { getByTestId } = render( + , + ); + + getByTestId('custom-root'); + getByTestId('custom-badge'); + }); + + it('allows modifying slots props using the slotProps prop', () => { + const { getByTestId } = render( + , + ); + + getByTestId('custom-root'); + getByTestId('custom-badge'); + }); + }); + it('retains anchorOrigin, content, color, max, overlap and variant when invisible is true for consistent disappearing transition', () => { const { container, setProps } = render( , diff --git a/packages/mui-material/src/Dialog/Dialog.js b/packages/mui-material/src/Dialog/Dialog.js index dea7b6fa1b194e..eb31fd065a93d8 100644 --- a/packages/mui-material/src/Dialog/Dialog.js +++ b/packages/mui-material/src/Dialog/Dialog.js @@ -298,8 +298,8 @@ Dialog.propTypes /* remove-proptypes */ = { 'aria-labelledby': PropTypes.string, /** * A backdrop component. This prop enables custom backdrop rendering. - * @deprecated Use `components.Backdrop` instead. While this prop currently works, it will be removed in the next major version. - * Use the `components.Backdrop` prop to make your application ready for the next version of Material UI. + * @deprecated Use `slots.backdrop` instead. While this prop currently works, it will be removed in the next major version. + * Use the `slots.backdrop` prop to make your application ready for the next version of Material UI. * @default styled(Backdrop, { * name: 'MuiModal', * slot: 'Backdrop', diff --git a/packages/mui-material/src/Modal/Modal.d.ts b/packages/mui-material/src/Modal/Modal.d.ts index 66b0d3f19ee7e7..4f6c75e0180538 100644 --- a/packages/mui-material/src/Modal/Modal.d.ts +++ b/packages/mui-material/src/Modal/Modal.d.ts @@ -1,7 +1,11 @@ import * as React from 'react'; import { SxProps } from '@mui/system'; import { OverrideProps } from '@mui/types'; -import { ExtendModalUnstyledTypeMap, ExtendModalUnstyled } from '@mui/base/ModalUnstyled'; +import { + ExtendModalUnstyledTypeMap, + ExtendModalUnstyled, + ModalUnstyledTypeMap, +} from '@mui/base/ModalUnstyled'; import { Theme } from '../styles'; import { BackdropProps } from '../Backdrop'; @@ -9,8 +13,8 @@ export type ModalTypeMap = ExtendMo props: P & { /** * A backdrop component. This prop enables custom backdrop rendering. - * @deprecated Use `components.Backdrop` instead. While this prop currently works, it will be removed in the next major version. - * Use the `components.Backdrop` prop to make your application ready for the next version of Material UI. + * @deprecated Use `slots.backdrop` instead. While this prop currently works, it will be removed in the next major version. + * Use the `slots.backdrop` prop to make your application ready for the next version of Material UI. * @default styled(Backdrop, { * name: 'MuiModal', * slot: 'Backdrop', @@ -24,9 +28,23 @@ export type ModalTypeMap = ExtendMo BackdropComponent?: React.ElementType; /** * Props applied to the [`Backdrop`](/material-ui/api/backdrop/) element. - * @deprecated Use `componentsProps.backdrop` instead. + * @deprecated Use `slotProps.backdrop` instead. */ BackdropProps?: Partial; + /** + * The components used for each slot inside the Modal. + * Either a string to use a HTML element or a component. + * @default {} + */ + components?: { + Root?: React.ElementType; + Backdrop?: React.ElementType; + }; + /** + * The props used for each slot inside the Modal. + * @default {} + */ + componentsProps?: ModalUnstyledTypeMap['props']['slotProps']; /** * The system prop that allows defining system overrides as well as additional CSS styles. */ @@ -35,7 +53,7 @@ export type ModalTypeMap = ExtendMo defaultComponent: D; }>; -type ModalRootProps = NonNullable['root']; +type ModalRootProps = NonNullable['root']; export declare const ModalRoot: React.FC; diff --git a/packages/mui-material/src/Modal/Modal.js b/packages/mui-material/src/Modal/Modal.js index 92d2eadabb778e..2a5b7808b3f226 100644 --- a/packages/mui-material/src/Modal/Modal.js +++ b/packages/mui-material/src/Modal/Modal.js @@ -75,6 +75,8 @@ const Modal = React.forwardRef(function Modal(inProps, ref) { disableScrollLock = false, hideBackdrop = false, keepMounted = false, + slotProps, + slots, // eslint-disable-next-line react/prop-types theme, ...other @@ -102,23 +104,26 @@ const Modal = React.forwardRef(function Modal(inProps, ref) { const classes = extendUtilityClasses(ownerState); - const Root = components.Root ?? component ?? ModalRoot; + const RootSlot = slots?.root ?? components.Root ?? ModalRoot; + const BackdropSlot = slots?.backdrop ?? components.Backdrop ?? BackdropComponent; + + const rootSlotProps = slotProps?.root ?? componentsProps.root; + const backdropSlotProps = slotProps?.backdrop ?? componentsProps.backdrop; return ( ({ - ...resolveComponentProps(componentsProps.root, ownerState), - ...(!isHostComponent(Root) && { as: component, theme }), + ...resolveComponentProps(rootSlotProps, ownerState), + ...(!isHostComponent(RootSlot) && { as: component, theme }), }), backdrop: () => ({ ...BackdropProps, - ...resolveComponentProps(componentsProps.backdrop, ownerState), + ...resolveComponentProps(backdropSlotProps, ownerState), }), }} onTransitionEnter={() => setExited(false)} @@ -140,8 +145,8 @@ Modal.propTypes /* remove-proptypes */ = { // ---------------------------------------------------------------------- /** * A backdrop component. This prop enables custom backdrop rendering. - * @deprecated Use `components.Backdrop` instead. While this prop currently works, it will be removed in the next major version. - * Use the `components.Backdrop` prop to make your application ready for the next version of Material UI. + * @deprecated Use `slots.backdrop` instead. While this prop currently works, it will be removed in the next major version. + * Use the `slots.backdrop` prop to make your application ready for the next version of Material UI. * @default styled(Backdrop, { * name: 'MuiModal', * slot: 'Backdrop', @@ -155,7 +160,7 @@ Modal.propTypes /* remove-proptypes */ = { BackdropComponent: PropTypes.elementType, /** * Props applied to the [`Backdrop`](/material-ui/api/backdrop/) element. - * @deprecated Use `componentsProps.backdrop` instead. + * @deprecated Use `slotProps.backdrop` instead. */ BackdropProps: PropTypes.object, /** @@ -272,6 +277,23 @@ Modal.propTypes /* remove-proptypes */ = { * If `true`, the component is shown. */ open: PropTypes.bool.isRequired, + /** + * The props used for each slot inside the Modal. + * @default {} + */ + slotProps: PropTypes.shape({ + backdrop: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the Modal. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + backdrop: PropTypes.elementType, + root: PropTypes.elementType, + }), /** * The system prop that allows defining system overrides as well as additional CSS styles. */ diff --git a/packages/mui-material/src/Popper/Popper.tsx b/packages/mui-material/src/Popper/Popper.tsx index 17c280219149ba..e62ece2792ba94 100644 --- a/packages/mui-material/src/Popper/Popper.tsx +++ b/packages/mui-material/src/Popper/Popper.tsx @@ -6,6 +6,20 @@ import * as React from 'react'; import { styled, Theme, useThemeProps } from '../styles'; export type PopperProps = Omit & { + /** + * The components used for each slot inside the Popper. + * Either a string to use a HTML element or a component. + * @default {} + */ + components?: { + Root?: React.ElementType; + }; + + /** + * The props used for each slot inside the Popper. + * @default {} + */ + componentsProps?: PopperUnstyledProps['slotProps']; /** * The system prop that allows defining system overrides as well as additional CSS styles. */ @@ -35,8 +49,22 @@ const Popper = React.forwardRef(function Popper( ref: React.ForwardedRef, ) { const theme = useTheme<{ direction?: Direction }>(); - const props = useThemeProps({ props: inProps, name: 'MuiPopper' }); - return ; + const { components, componentsProps, slots, slotProps, ...other } = useThemeProps({ + props: inProps, + name: 'MuiPopper', + }); + + const RootComponent = slots?.root ?? components?.Root; + + return ( + + ); }); Popper.propTypes /* remove-proptypes */ = { @@ -191,6 +219,21 @@ Popper.propTypes /* remove-proptypes */ = { * A ref that points to the used popper instance. */ popperRef: refType, + /** + * The props used for each slot inside the Popper. + * @default {} + */ + slotProps: PropTypes.shape({ + root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + }), + /** + * The components used for each slot inside the Popper. + * Either a string to use a HTML element or a component. + * @default {} + */ + slots: PropTypes.shape({ + root: PropTypes.elementType, + }), /** * The system prop that allows defining system overrides as well as additional CSS styles. */ diff --git a/packages/mui-material/src/Slider/Slider.d.ts b/packages/mui-material/src/Slider/Slider.d.ts index 41ad1ef5637e61..78a7f1b9a4ccc2 100644 --- a/packages/mui-material/src/Slider/Slider.d.ts +++ b/packages/mui-material/src/Slider/Slider.d.ts @@ -26,6 +26,22 @@ export type SliderTypeMap< * @default 'primary' */ color?: OverridableStringUnion<'primary' | 'secondary', SliderPropsColorOverrides>; + /** + * The components used for each slot inside the Slider. + * Either a string to use a HTML element or a component. + * @default {} + */ + components?: { + Root?: React.ElementType; + Track?: React.ElementType; + Rail?: React.ElementType; + Thumb?: React.ElementType; + Mark?: React.ElementType; + MarkLabel?: React.ElementType; + ValueLabel?: React.ElementType; + Input?: React.ElementType; + }; + componentsProps?: SliderUnstyledTypeMap['props']['slotProps']; /** * Override or extend the styles applied to the component. */ diff --git a/packages/mui-material/src/Slider/Slider.js b/packages/mui-material/src/Slider/Slider.js index 9accffdf00a555..1dfd07e8551c12 100644 --- a/packages/mui-material/src/Slider/Slider.js +++ b/packages/mui-material/src/Slider/Slider.js @@ -489,6 +489,8 @@ const Slider = React.forwardRef(function Slider(inputProps, ref) { componentsProps = {}, color = 'primary', size = 'medium', + slotProps, + slots, ...other } = props; @@ -496,47 +498,70 @@ const Slider = React.forwardRef(function Slider(inputProps, ref) { const classes = extendUtilityClasses(ownerState); + // support both `slots` and `components` for backward compatibility + const RootSlot = slots?.root ?? components.Root ?? SliderRoot; + const RailSlot = slots?.rail ?? components.Rail ?? SliderRail; + const TrackSlot = slots?.track ?? components.Track ?? SliderTrack; + const ThumbSlot = slots?.thumb ?? components.Thumb ?? SliderThumb; + const ValueLabelSlot = slots?.valueLabel ?? components.ValueLabel ?? SliderValueLabel; + const MarkSlot = slots?.mark ?? components.Mark ?? SliderMark; + const MarkLabelSlot = slots?.markLabel ?? components.MarkLabel ?? SliderMarkLabel; + const InputSlot = slots?.input ?? components.Input; + + const rootSlotProps = slotProps?.root ?? componentsProps.root; + const railSlotProps = slotProps?.rail ?? componentsProps.rail; + const trackSlotProps = slotProps?.track ?? componentsProps.track; + const thumbSlotProps = slotProps?.thumb ?? componentsProps.thumb; + const valueLabelSlotProps = slotProps?.valueLabel ?? componentsProps.valueLabel; + const markSlotProps = slotProps?.mark ?? componentsProps.mark; + const markLabelSlotProps = slotProps?.markLabel ?? componentsProps.markLabel; + const inputSlotProps = slotProps?.input ?? componentsProps.input; + return ( UnstyledConformanceOptions, -) { +function testSlotsProp(element: React.ReactElement, getOptions: () => UnstyledConformanceOptions) { const { render, slots, testComponentPropWith: Element = 'div' } = getOptions(); if (!render) { @@ -128,34 +124,34 @@ function testComponentsProp( )); forEachSlot(slots, (slotName, slotOptions) => { - it(`allows overriding the ${capitalize(slotName)} slot with a component`, () => { + it(`allows overriding the ${slotName} slot with a component`, () => { const slotComponent = slotOptions.testWithComponent ?? CustomComponent; const components = { - [capitalize(slotName)]: slotComponent, + [slotName]: slotComponent, }; - const { getByTestId } = render(React.cloneElement(element, { components })); + const { getByTestId } = render(React.cloneElement(element, { slots: components })); const renderedElement = getByTestId('custom'); expect(renderedElement).to.have.class(slotOptions.expectedClassName); }); if (slotOptions.testWithElement !== null) { - it(`allows overriding the ${capitalize(slotName)} slot with an element`, () => { + it(`allows overriding the ${slotName} slot with an element`, () => { const slotElement = slotOptions.testWithElement ?? 'i'; const components = { - [capitalize(slotName)]: slotElement, + [slotName]: slotElement, }; - const componentsProps = { + const slotProps = { [slotName]: { 'data-testid': 'customized', }, }; const { getByTestId } = render( - React.cloneElement(element, { components, componentsProps }), + React.cloneElement(element, { slots: components, slotProps }), ); const renderedElement = getByTestId('customized'); expect(renderedElement.nodeName.toLowerCase()).to.equal(slotElement); @@ -164,18 +160,18 @@ function testComponentsProp( } if (slotOptions.isOptional) { - it(`alows omitting the optional ${capitalize(slotName)} slot by providing null`, () => { + it(`alows omitting the optional ${slotName} slot by providing null`, () => { const components = { - [capitalize(slotName)]: null, + [slotName]: null, }; - const { container } = render(React.cloneElement(element, { components })); + const { container } = render(React.cloneElement(element, { slots: components })); expect(container.querySelectorAll(`.${slotOptions.expectedClassName}`)).to.have.length(0); }); } }); - it('uses the component provided in component prop when both component and components.Root are provided', () => { + it('uses the component provided in the `component` prop when both `component` and `slots.root` are provided', () => { const RootComponentA = React.forwardRef( ({ children }: React.PropsWithChildren<{}>, ref: React.Ref) => ( // @ts-ignore @@ -197,7 +193,7 @@ function testComponentsProp( const { queryByTestId } = render( React.cloneElement(element, { component: RootComponentA, - components: { Root: RootComponentB }, + slots: { root: RootComponentB }, }), ); @@ -206,7 +202,7 @@ function testComponentsProp( }); } -function testComponentsPropsProp( +function testSlotPropsProp( element: React.ReactElement, getOptions: () => UnstyledConformanceOptions, ) { @@ -221,30 +217,30 @@ function testComponentsPropsProp( } forEachSlot(slots, (slotName, slotOptions) => { - it(`sets custom properties on ${capitalize(slotName)} slot's element`, () => { - const componentsProps = { + it(`sets custom properties on the ${slotName} slot's element`, () => { + const slotProps = { [slotName]: { 'data-testid': 'custom', }, }; - const { getByTestId } = render(React.cloneElement(element, { componentsProps })); + const { getByTestId } = render(React.cloneElement(element, { slotProps })); expect(getByTestId('custom')).to.have.class(slotOptions.expectedClassName); }); - it(`merges the class names provided in componentsProps.${slotName} with the built-in ones`, () => { - const componentsProps = { + it(`merges the class names provided in slotsProps.${slotName} with the built-in ones`, () => { + const slotProps = { [slotName]: { 'data-testid': 'custom', className: randomStringValue(), }, }; - const { getByTestId } = render(React.cloneElement(element, { componentsProps })); + const { getByTestId } = render(React.cloneElement(element, { slotProps })); expect(getByTestId('custom')).to.have.class(slotOptions.expectedClassName); - expect(getByTestId('custom')).to.have.class(componentsProps[slotName].className); + expect(getByTestId('custom')).to.have.class(slotProps[slotName].className); }); }); } @@ -253,7 +249,7 @@ interface TestOwnerState { 'data-testid'?: string; } -function testComponentsPropsCallbacks( +function testSlotPropsCallbacks( element: React.ReactElement, getOptions: () => UnstyledConformanceOptions, ) { @@ -268,13 +264,11 @@ function testComponentsPropsCallbacks( } forEachSlot(slots, (slotName, slotOptions) => { - it(`sets custom properties on ${capitalize( - slotName, - )} slot's element with a callback function`, () => { + it(`sets custom properties on the ${slotName} slot's element with a callback function`, () => { const testId = randomStringValue(); const className = randomStringValue(); - const componentsProps = { + const slotProps = { [slotName]: (ownerState: TestOwnerState) => ({ 'data-testid': `${ownerState['data-testid']}-${slotName}`, className, @@ -282,7 +276,7 @@ function testComponentsPropsCallbacks( }; const { getByTestId } = render( - React.cloneElement(element, { componentsProps, 'data-testid': testId }), + React.cloneElement(element, { slotProps, 'data-testid': testId }), ); expect(getByTestId(`${testId}-${slotName}`)).to.have.class(slotOptions.expectedClassName); @@ -306,7 +300,7 @@ function testOwnerStatePropagation( } forEachSlot(slots, (slotName) => { - it(`sets the ownerState prop on ${capitalize(slotName)} slot's component`, () => { + it(`sets the ownerState prop on the ${slotName} slot's component`, () => { const TestComponent = React.forwardRef( ({ ownerState, expectedOwnerState }: WithOwnerState, ref: React.Ref) => { expect(ownerState).not.to.equal(undefined); @@ -316,11 +310,11 @@ function testOwnerStatePropagation( }, ); - const components = { - [capitalize(slotName)]: TestComponent, + const slotOverrides = { + [slotName]: TestComponent, }; - const componentsProps = { + const slotProps = { [slotName]: { expectedOwnerState: { id: 'foo', @@ -328,16 +322,16 @@ function testOwnerStatePropagation( }, }; - render(React.cloneElement(element, { components, componentsProps, id: 'foo' })); + render(React.cloneElement(element, { slots: slotOverrides, slotProps, id: 'foo' })); }); }); } const fullSuite = { componentProp: testComponentProp, - componentsProp: testComponentsProp, - componentsPropsProp: testComponentsPropsProp, - componentsPropsCallbacks: testComponentsPropsCallbacks, + slotsProp: testSlotsProp, + slotPropsProp: testSlotPropsProp, + slotPropsCallbacks: testSlotPropsCallbacks, mergeClassName: testClassName, propsSpread: testPropForwarding, reactTestRenderer: testReactTestRenderer,