Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[TablePagination] Add the rest of slots and slotProps. #44570

Merged
merged 17 commits into from
Dec 20, 2024
Merged
Next Next commit
complete slots and slotProps
siriwatknp committed Nov 27, 2024
commit 82b074f0fc3b46ad7e797b2e5a06cff60942e6e1
82 changes: 64 additions & 18 deletions packages/mui-material/src/TablePagination/TablePagination.d.ts
Original file line number Diff line number Diff line change
@@ -2,11 +2,14 @@ import * as React from 'react';
import { SxProps } from '@mui/system';
import { Theme } from '../styles';
import { OverridableComponent, OverrideProps } from '../OverridableComponent';
import { TablePaginationActionsProps } from './TablePaginationActions';
import { TablePaginationActionsProps, TablePaginationActionsSlots } from './TablePaginationActions';
import { TableCellProps } from '../TableCell';
import { IconButtonProps } from '../IconButton';
import { SelectProps } from '../Select';
import { TablePaginationClasses } from './tablePaginationClasses';
import { CreateSlotsAndSlotProps, SlotProps } from '../utils/types';
import { ToolbarOwnProps } from '../Toolbar';
import { MenuItemOwnProps } from '../MenuItem';

export interface LabelDisplayedRowsArgs {
from: number;
@@ -15,6 +18,63 @@ export interface LabelDisplayedRowsArgs {
page: number;
}

export interface TablePaginationRootSlotPropsOverrides {}

export interface TablePaginationToolbarSlotPropsOverrides {}

export interface TablePaginationSpacerSlotPropsOverrides {}

export interface TablePaginationSelectLabelSlotPropsOverrides {}

export interface TablePaginationMenuItemSlotPropsOverrides {}

export interface TablePaginationDisplayedRowsSlotPropsOverrides {}

export interface TablePaginationSlots {
root: React.ElementType;
toolbar: React.ElementType;
spacer: React.ElementType;
selectLabel: React.ElementType;
select: React.ElementType;
menuItem: React.ElementType;
displayedRows: React.ElementType;
actions: TablePaginationActionsSlots;
}

export type TablePaginationSlotsAndSlotProps = CreateSlotsAndSlotProps<
TablePaginationSlots,
{
root: SlotProps<
React.ElementType<TableCellProps>,
TablePaginationRootSlotPropsOverrides,
TablePaginationOwnerState
>;
toolbar: SlotProps<
React.ElementType<ToolbarOwnProps>,
TablePaginationToolbarSlotPropsOverrides,
TablePaginationOwnerState
>;
spacer: SlotProps<'div', TablePaginationSpacerSlotPropsOverrides, TablePaginationOwnerState>;
selectLabel: SlotProps<
'p',
TablePaginationSelectLabelSlotPropsOverrides,
TablePaginationOwnerState
>;
menuItem: SlotProps<
React.ElementType<MenuItemOwnProps>,
TablePaginationMenuItemSlotPropsOverrides,
TablePaginationOwnerState
>;
displayedRows: SlotProps<
'p',
TablePaginationDisplayedRowsSlotPropsOverrides,
TablePaginationOwnerState
>;
actions: TablePaginationActionsProps['slotProps'];
select: Partial<SelectProps>;
}
>;

/**
* This type is kept for compatibility. Use `TablePaginationOwnProps` instead.
*/
@@ -134,30 +194,16 @@ export interface TablePaginationOwnProps extends TablePaginationBaseProps {
* @default false
*/
showLastButton?: boolean;
/**
* The props used for each slot inside the TablePagination.
* @default {}
*/
slotProps?: {
actions?: TablePaginationActionsProps['slotProps'];
select?: Partial<SelectProps>;
};
/**
* The components used for each slot inside the TablePagination.
* Either a string to use a HTML element or a component.
* @default {}
*/
slots?: {
actions?: TablePaginationActionsProps['slots'];
};
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme>;
}

export interface TablePaginationOwnerState extends TablePaginationOwnProps {}

export interface TablePaginationTypeMap<AdditionalProps, RootComponent extends React.ElementType> {
props: AdditionalProps & TablePaginationOwnProps;
props: AdditionalProps & TablePaginationOwnProps & TablePaginationSlotsAndSlotProps;
defaultComponent: RootComponent;
}

104 changes: 77 additions & 27 deletions packages/mui-material/src/TablePagination/TablePagination.js
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@ import clsx from 'clsx';
import integerPropType from '@mui/utils/integerPropType';
import chainPropTypes from '@mui/utils/chainPropTypes';
import composeClasses from '@mui/utils/composeClasses';
import isHostComponent from '../utils/isHostComponent';
import { styled } from '../zero-styled';
import memoTheme from '../utils/memoTheme';
import { useDefaultProps } from '../DefaultPropsProvider';
@@ -17,6 +16,7 @@ import Toolbar from '../Toolbar';
import TablePaginationActions from './TablePaginationActions';
import useId from '../utils/useId';
import tablePaginationClasses, { getTablePaginationUtilityClass } from './tablePaginationClasses';
import useSlot from '../utils/useSlot';

const TablePaginationRoot = styled(TableCell, {
name: 'MuiTablePagination',
@@ -152,7 +152,6 @@ const TablePagination = React.forwardRef(function TablePagination(inProps, ref)
const {
ActionsComponent = TablePaginationActions,
backIconButtonProps,
className,
colSpan: colSpanProp,
component = TableCell,
count,
@@ -196,25 +195,78 @@ const TablePagination = React.forwardRef(function TablePagination(inProps, ref)
return rowsPerPage === -1 ? count : Math.min(count, (page + 1) * rowsPerPage);
};

const externalForwardedProps = { slots, slotProps };

const [RootSlot, rootSlotProps] = useSlot('root', {
ref,
className: classes.root,
elementType: TablePaginationRoot,
externalForwardedProps: {
...externalForwardedProps,
component,
...other,
},
ownerState,
additionalProps: {
colSpan,
},
});

const [ToolbarSlot, toolbarSlotProps] = useSlot('toolbar', {
className: classes.toolbar,
elementType: TablePaginationToolbar,
externalForwardedProps,
ownerState,
});

const [SpacerSlot, spacerSlotProps] = useSlot('spacer', {
className: classes.spacer,
elementType: TablePaginationSpacer,
externalForwardedProps,
ownerState,
});

const [SelectLabelSlot, selectLabelSlotProps] = useSlot('selectLabel', {
className: classes.selectLabel,
elementType: TablePaginationSelectLabel,
externalForwardedProps,
ownerState,
additionalProps: {
id: labelId,
},
});

const [SelectSlot, selectSlotProps] = useSlot('select', {
className: classes.select,
elementType: TablePaginationSelect,
externalForwardedProps,
ownerState,
});

const [MenuItemSlot, menuItemSlotProps] = useSlot('menuItem', {
className: classes.menuItem,
elementType: MenuItemComponent,
externalForwardedProps,
ownerState,
});

const [DisplayedRows, displayedRowsProps] = useSlot('displayedRows', {
className: classes.displayedRows,
elementType: TablePaginationDisplayedRows,
externalForwardedProps,
ownerState,
});

return (
<TablePaginationRoot
colSpan={colSpan}
ref={ref}
as={component}
ownerState={ownerState}
className={clsx(classes.root, className)}
{...other}
>
<TablePaginationToolbar className={classes.toolbar}>
<TablePaginationSpacer className={classes.spacer} />
<RootSlot {...rootSlotProps}>
<ToolbarSlot {...toolbarSlotProps}>
<SpacerSlot {...spacerSlotProps} />
{rowsPerPageOptions.length > 1 && (
<TablePaginationSelectLabel className={classes.selectLabel} id={labelId}>
{labelRowsPerPage}
</TablePaginationSelectLabel>
<SelectLabelSlot {...selectLabelSlotProps}>{labelRowsPerPage}</SelectLabelSlot>
)}

{rowsPerPageOptions.length > 1 && (
<TablePaginationSelect
<SelectSlot
variant="standard"
{...(!selectProps.variant && { input: <InputBase /> })}
value={rowsPerPage}
@@ -231,30 +283,28 @@ const TablePagination = React.forwardRef(function TablePagination(inProps, ref)
icon: clsx(classes.selectIcon, (selectProps.classes || {}).icon),
}}
disabled={disabled}
{...selectSlotProps}
>
{rowsPerPageOptions.map((rowsPerPageOption) => (
<MenuItemComponent
{...(!isHostComponent(MenuItemComponent) && {
ownerState,
})}
className={classes.menuItem}
<MenuItemSlot
{...menuItemSlotProps}
key={rowsPerPageOption.label ? rowsPerPageOption.label : rowsPerPageOption}
value={rowsPerPageOption.value ? rowsPerPageOption.value : rowsPerPageOption}
>
{rowsPerPageOption.label ? rowsPerPageOption.label : rowsPerPageOption}
</MenuItemComponent>
</MenuItemSlot>
))}
</TablePaginationSelect>
</SelectSlot>
)}

<TablePaginationDisplayedRows className={classes.displayedRows}>
<DisplayedRows {...displayedRowsProps}>
{labelDisplayedRows({
from: count === 0 ? 0 : page * rowsPerPage + 1,
to: getLabelDisplayedRowsTo(),
count: count === -1 ? -1 : count,
page,
})}
</TablePaginationDisplayedRows>
</DisplayedRows>
<ActionsComponent
className={classes.actions}
backIconButtonProps={backIconButtonProps}
@@ -270,8 +320,8 @@ const TablePagination = React.forwardRef(function TablePagination(inProps, ref)
getItemAriaLabel={getItemAriaLabel}
disabled={disabled}
/>
</TablePaginationToolbar>
</TablePaginationRoot>
</ToolbarSlot>
</RootSlot>
);
});

Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as React from 'react';
import TablePagination from '@mui/material/TablePagination';
import TablePagination, { TablePaginationOwnerState } from '@mui/material/TablePagination';
import SvgIcon from '@mui/material/SvgIcon';
import IconButton, { IconButtonProps } from '@mui/material/IconButton';
import { expectType } from '@mui/types';

function SampleIcon() {
return (
@@ -92,3 +93,84 @@ function classesTest() {
},
}}
/>;
<TablePagination
count={1}
rowsPerPage={1}
page={1}
onPageChange={() => {}}
slots={{
root: 'div',
toolbar: 'div',
spacer: 'div',
displayedRows: 'p',
select: 'select',
selectLabel: 'label',
menuItem: 'div',
}}
slotProps={{
root: {
id: 'root',
},
toolbar: {
id: 'toolbar',
disableGutters: true,
},
displayedRows: {
id: 'displayedRows',
},
menuItem: {
id: 'menuItem',
},
selectLabel: {
id: 'selectLabel',
},
spacer: {
id: 'spacer',
},
}}
/>;
<TablePagination
count={1}
rowsPerPage={1}
page={1}
onPageChange={() => {}}
slotProps={{
root: (ownerState) => {
expectType<TablePaginationOwnerState, typeof ownerState>(ownerState);
return {
id: 'root',
};
},
toolbar: (ownerState) => {
expectType<TablePaginationOwnerState, typeof ownerState>(ownerState);
return {
id: 'toolbar',
disableGutters: true,
};
},
displayedRows: (ownerState) => {
expectType<TablePaginationOwnerState, typeof ownerState>(ownerState);
return {
id: 'displayedRows',
};
},
menuItem: (ownerState) => {
expectType<TablePaginationOwnerState, typeof ownerState>(ownerState);
return {
id: 'menuItem',
};
},
selectLabel: (ownerState) => {
expectType<TablePaginationOwnerState, typeof ownerState>(ownerState);
return {
id: 'selectLabel',
};
},
spacer: (ownerState) => {
expectType<TablePaginationOwnerState, typeof ownerState>(ownerState);
return {
id: 'spacer',
};
},
}}
/>;