-
-
Notifications
You must be signed in to change notification settings - Fork 31.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[material ui][PaginationItem] Pagination Item component crashes due to a null check missing for contrastText #42055
Comments
@noobDev31 Thanks for reporting this, would you mind providing a minimal reproduction? You can fork this template: https://stackblitz.com/edit/stackblitz-starters-maxhor?file=src%2FApp.tsx PS here are some tips for providing a minimal repro: https://stackoverflow.com/help/mcve |
@mj12albert For some reason i get some errors on the above stackblitz link - |
@siriwatknp Wouldn't it be right to do a add a null check on the code on your side? actually i am passing default color as 'brand'(our overridden colour) and without the ThemeProvider wrapping it, it breaks We're doing styling through the ThemeProvider like with the below code - import {ComponentsProps, ComponentsOverrides, ComponentsVariants, Theme} from '@mui/material';
declare module '@mui/material/PaginationItem' {
interface PaginationItemPropsColorOverrides {
brand: true;
}
}
export const CorePaginationItem: {
// the below 3 lines are: TypeScript definition of this object according to themeProvider
defaultProps?: ComponentsProps['MuiPaginationItem'];
styleOverrides?: ComponentsOverrides<Theme>['MuiPaginationItem'];
variants?: ComponentsVariants['MuiPaginationItem'];
} = {
styleOverrides: {
root: ({theme}: {theme: Theme}) => ({
fontSize: 30,
width: 32,
height: 32,
lineHeight: '17px',
'& .lcep-icon-svg': {
width: 24,
height: 24,
display: 'flex',
alignItems: 'center'
},
'&.MuiPaginationItem-page': {
fontSize: theme.typography.body1.fontSize
},
'&.MuiPaginationItem-textBrand': {
'&.Mui-selected': {
backgroundColor: theme.palette.brand.main
}
},
'&.MuiPaginationItem-textPrimary': {
'&.Mui-selected': {
backgroundColor: theme.palette.primary.main
}
},
'&.MuiPaginationItem-textSecondary': {
'&.Mui-selected': {
backgroundColor: theme.palette.secondary.main
}
},
'&.Mui-disabled': {
color: theme.palette.text.disabled
},
'&.Mui-disabled.Mui-selected': {
backgroundColor: theme.palette.action.disabledBackground
}
})
}
}; import {ComponentsProps, ComponentsOverrides, ComponentsVariants, Theme} from '@mui/material';
declare module '@mui/material/Pagination' {
interface PaginationPropsColorOverrides {
brand: true;
}
}
export const CorePagination: {
// the below 3 lines are: TypeScript definition of this object according to themeProvider
defaultProps?: ComponentsProps['MuiPagination'];
styleOverrides?: ComponentsOverrides<Theme>['MuiPagination'];
variants?: ComponentsVariants['MuiPagination'];
} = {
styleOverrides: {
ul: {
'& li': {
width: 44,
height: 60,
display: 'flex',
alignItems: 'center'
}
}
}
}; import {createTheme, darken, getLuminance, lighten, PaletteColor, SimplePaletteColorOptions, Theme, PaletteMode} from '@mui/material';
import type {} from '@mui/x-data-grid-premium/themeAugmentation';
import {getConfig} from './config';
import {CorePagination} from './corePagination';
import {Property} from 'csstype';
import {getCoreLocale, getDatePickerLocale, getGridLocale} from '../utils/localisationUtils';
export type ResponsivenessMode = 'Screen' | 'Container';
// typescript support for theme custom fields
declare module '@mui/material/styles' {
interface Palette {
brand: PaletteColor;
ink: PaletteColor;
surface: PaletteColor;
paper: PaletteColor;
special1: PaletteColor;
special2: PaletteColor;
special3: PaletteColor;
special4: PaletteColor;
}
interface PaletteOptions {
brand: SimplePaletteColorOptions;
ink: SimplePaletteColorOptions;
surface: SimplePaletteColorOptions;
paper: SimplePaletteColorOptions;
special1: SimplePaletteColorOptions;
special2: SimplePaletteColorOptions;
special3: SimplePaletteColorOptions;
special4: SimplePaletteColorOptions;
}
interface Theme {
responsiveness: {
responsivenessMode: ResponsivenessMode;
containerName?: string;
};
}
interface ThemeOptions {
responsiveness: {
responsivenessMode: ResponsivenessMode;
containerName?: string;
};
}
}
const modeNumber = (mode: PaletteMode, numberLight: string, numberDark: string): number => {
return (mode === 'light') ? Number(numberLight) : Number(numberDark);
};
const modeColor = (mode: PaletteMode, colorLight: string, colorDark: string): string => {
return (mode === 'light') ? colorLight : colorDark;
};
const paletteModeColor = (mode: PaletteMode, colorLight: string, colorDark: string, config: Record<string, string>): SimplePaletteColorOptions => {
const tonalOffsetLight = modeNumber(mode, config.tonalOffsetLightLight, config.tonalOffsetLightDark);
const tonalOffsetDark = modeNumber(mode, config.tonalOffsetDarkLight, config.tonalOffsetDarkDark);
const main = modeColor(mode, colorLight, colorDark);
const light = lighten(main, tonalOffsetLight);
const dark = darken(main, tonalOffsetDark);
const contrastText = (getLuminance(main) > 0.5) ? config.black : config.white;
return {main, light, dark, contrastText};
};
const baseTheme = (themeConfig: IThemeConfig = {}, mode: PaletteMode = 'light', responsivenessMode: ResponsivenessMode = 'Screen',
containerName: string = '', locale = 'en-US'): Theme => {
const config = getConfig(themeConfig);
return createTheme({
breakpoints: {
values: {
xs: 0,
sm: 768,
md: 960,
lg: 1200,
xl: 1600
}
},
responsiveness: {
responsivenessMode,
containerName
},
palette: {
mode,
common: {
black: config.black,
white: config.white
},
background: {
default: modeColor(mode, config.surfaceLight, config.surfaceDark),
paper: modeColor(mode, config.paperLight, config.paperDark)
},
primary: paletteModeColor(mode, config.primaryLight, config.primaryDark, config),
secondary: paletteModeColor(mode, config.secondaryLight, config.secondaryDark, config),
ink: paletteModeColor(mode, config.inkLight, config.inkDark, config),
surface: paletteModeColor(mode, config.surfaceLight, config.surfaceDark, config),
paper: paletteModeColor(mode, config.paperLight, config.paperDark, config),
brand: paletteModeColor(mode, config.brandLight, config.brandDark, config),
special1: paletteModeColor(mode, config.special1Light, config.special1Dark, config),
special2: paletteModeColor(mode, config.special2Light, config.special2Dark, config),
special3: paletteModeColor(mode, config.special3Light, config.special3Dark, config),
special4: paletteModeColor(mode, config.special4Light, config.special4Dark, config),
error: paletteModeColor(mode, config.errorLight, config.errorDark, config),
success: paletteModeColor(mode, config.successLight, config.successDark, config),
warning: paletteModeColor(mode, config.warningLight, config.warningDark, config),
info: paletteModeColor(mode, config.infoLight, config.infoDark, config),
grey: {
50: modeColor(mode, config.grey50Light, config.grey50Dark),
100: modeColor(mode, config.grey100Light, config.grey100Dark),
200: modeColor(mode, config.grey200Light, config.grey200Dark),
300: modeColor(mode, config.grey300Light, config.grey300Dark),
400: modeColor(mode, config.grey400Light, config.grey400Dark),
500: modeColor(mode, config.grey500Light, config.grey500Dark),
600: modeColor(mode, config.grey600Light, config.grey600Dark),
700: modeColor(mode, config.grey700Light, config.grey700Dark),
800: modeColor(mode, config.grey800Light, config.grey800Dark),
900: modeColor(mode, config.grey900Light, config.grey900Dark)
},
divider: modeColor(mode, config.dividerLight, config.dividerDark),
text: {
primary: modeColor(mode, config.textPrimaryLight, config.textPrimaryDark),
secondary: modeColor(mode, config.textSecondaryLight, config.textSecondaryDark),
disabled: modeColor(mode, config.textDisabledLight, config.textDisabledDark)
},
action: {
disabled: modeColor(mode, config.disabledLight, config.disabledDark),
selected: modeColor(mode, config.selectedLight, config.selectedDark),
hover: modeColor(mode, config.hoverLight, config.hoverDark),
active: modeColor(mode, config.activeLight, config.activeDark),
focus: modeColor(mode, config.focusLight, config.focusDark),
disabledBackground: modeColor(mode, config.disabledBackgroundLight, config.disabledBackgroundDark),
hoverOpacity: modeNumber(mode, config.hoverOpacityLight, config.hoverOpacityDark),
selectedOpacity: modeNumber(mode, config.selectedOpacityLight, config.selectedOpacityDark),
disabledOpacity: modeNumber(mode, config.disabledOpacityLight, config.disabledOpacityDark),
focusOpacity: modeNumber(mode, config.focusOpacityLight, config.focusOpacityDark),
activatedOpacity: modeNumber(mode, config.activatedOpacityLight, config.activatedOpacityDark)
},
tonalOffset: {
light: modeNumber(mode, config.tonalOffsetLightLight, config.tonalOffsetLightDark),
dark: modeNumber(mode, config.tonalOffsetDarkLight, config.tonalOffsetDarkDark)
},
contrastThreshold: 4.5
},
typography: {
fontFamily: config.font,
htmlFontSize: 14,
fontSize: 14,
h1: {
fontFamily: config.fontH1,
fontSize: config.fontH1Size,
fontWeight: config.fontH1Weight,
lineHeight: config.fontH1LineHeight,
textTransform: config.fontH1TextTransform as Property.TextTransform
},
h2: {
fontFamily: config.fontH2,
fontSize: config.fontH2Size,
fontWeight: config.fontH2Weight,
lineHeight: config.fontH2LineHeight,
textTransform: config.fontH2TextTransform as Property.TextTransform
},
h3: {
fontFamily: config.fontH3,
fontSize: config.fontH3Size,
fontWeight: config.fontH3Weight,
lineHeight: config.fontH3LineHeight,
textTransform: config.fontH3TextTransform as Property.TextTransform
},
h4: {
fontFamily: config.fontH4,
fontSize: config.fontH4Size,
fontWeight: config.fontH4Weight,
lineHeight: config.fontH4LineHeight,
textTransform: config.fontH4TextTransform as Property.TextTransform
},
h5: {
fontFamily: config.fontH5,
fontSize: config.fontH5Size,
fontWeight: config.fontH5Weight,
lineHeight: config.fontH5LineHeight,
textTransform: config.fontH5TextTransform as Property.TextTransform
},
h6: {
fontFamily: config.fontH6,
fontSize: config.fontH6Size,
fontWeight: config.fontH6Weight,
lineHeight: config.fontH6LineHeight,
textTransform: config.fontH6TextTransform as Property.TextTransform
},
body1: {
fontFamily: config.fontBody1,
fontSize: config.fontBody1Size,
fontWeight: config.fontBody1Weight,
lineHeight: config.fontBody1LineHeight,
textTransform: config.fontBody1TextTransform as Property.TextTransform
},
body2: {
fontFamily: config.fontBody2,
fontSize: config.fontBody2Size,
fontWeight: config.fontBody2Weight,
lineHeight: config.fontBody2LineHeight,
textTransform: config.fontBody2TextTransform as Property.TextTransform
},
subtitle1: {
fontFamily: config.fontSubtitle1,
fontSize: config.fontSubtitle1Size,
fontWeight: config.fontSubtitle1Weight,
lineHeight: config.fontSubtitle1LineHeight,
textTransform: config.fontSubtitle1TextTransform as Property.TextTransform
},
subtitle2: {
fontFamily: config.fontSubtitle2,
fontSize: config.fontSubtitle2Size,
fontWeight: config.fontSubtitle2Weight,
lineHeight: config.fontSubtitle2LineHeight,
textTransform: config.fontSubtitle2TextTransform as Property.TextTransform
},
caption: {
fontFamily: config.fontCaption,
fontSize: config.fontCaptionSize,
fontWeight: config.fontCaptionWeight,
lineHeight: config.fontCaptionLineHeight,
textTransform: config.fontCaptionTextTransform as Property.TextTransform
},
overline: {
fontFamily: config.fontOverline,
fontSize: config.fontOverlineSize,
fontWeight: config.fontOverlineWeight,
lineHeight: config.fontOverlineLineHeight,
textTransform: config.fontOverlineTextTransform as Property.TextTransform
},
button: {
fontFamily: config.fontButton,
fontSize: config.fontButtonSize,
fontWeight: config.fontButtonWeight,
lineHeight: config.fontButtonLineHeight,
textTransform: config.fontButtonTextTransform as Property.TextTransform
}
},
shadows: [
'none',
'0 2px 8px 0 rgba(19, 19, 24, 0.16)',
'0 2px 16px 0 rgba(19, 19, 24, 0.16)',
'0 2px 24px 0 rgba(19, 19, 24, 0.20), 0 2px 8px 0 rgba(19, 19, 24, 0.12)',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
'',
''
],
spacing: (factor: number) => `${8 * factor}px`,
shape: {
borderRadius: Number(config.radiusBase)
},
transitions: {
easing: {
easeInOut: config.easeInOut,
easeOut: config.easeOut,
easeIn: config.easeIn,
sharp: config.sharp
},
duration: {
shortest: Number(config.shortest),
shorter: Number(config.shorter),
short: Number(config.short),
standard: Number(config.standard),
complex: Number(config.complex),
enteringScreen: Number(config.enteringScreen),
leavingScreen: Number(config.leavingScreen)
}
},
components: {
MuiPagination: CorePagination
}
},
getCoreLocale(locale),
getGridLocale(locale),
getDatePickerLocale(locale));
}; |
Guys any update on this @mj12albert @siriwatknp |
@noobDev31 Since you are defining a new custom color named |
👋 Thanks for using our open-source projects! We use GitHub issues exclusively as a bug and feature requests tracker, however, For support with Material UI please check out https://mui.com/material-ui/getting-started/support/. Thanks! If you have a question on Stack Overflow, you are welcome to link to it here, it might help others. |
@ZeeshanTamboli so there's no other way to get around this without the ThemeProvider right? |
Nope |
Steps to reproduce
Link to live example: (required)
Steps:
import {forwardRef, Ref, JSX} from 'react';
import {Pagination, PaginationProps, PaginationItem, useTheme, PaginationItemProps} from '@mui/material';
import {ChevronMiniLeftIcon, ChevronMiniRightIcon, PageFirstPageIcon, PageLastPageIcon} from '../../icons';
export type TPaginationProps = Omit<PaginationProps, 'color'> & {
color?: 'primary' | 'secondary' | 'brand';
};
const FirstIcon = (color: string): JSX.Element => {
return ;
};
const LastIcon = (color: string): JSX.Element => {
return ;
};
const PrevIcon = (color: string): JSX.Element => {
return ;
};
const NextIcon = (color: string): JSX.Element => {
return ;
};
const PaginationIcons = (props: TPaginationProps): PaginationItemProps['slots'] => {
const theme = useTheme();
const color = props.disabled ? theme.palette.text.disabled : theme.palette.text.primary;
const colorNavLeft = props.page === 1 ? theme.palette.text.disabled : color;
const colorNavRight = props.page === props.count ? theme.palette.text.disabled : color;
return {
first: () => FirstIcon(colorNavLeft),
previous: () => PrevIcon(colorNavLeft),
next: () => NextIcon(colorNavRight),
last: () => LastIcon(colorNavRight)
};
};
const Pagination = forwardRef((props: TPaginationProps, ref: Ref): JSX.Element => {
const {color = 'brand', ...restProps} = props;
return (
<Pagination
renderItem={(item) => (<PaginationItem slots={PaginationIcons(props)} {...item} />)}
{...restProps}
color={color}
ref={ref}
/>
);
});
export {Pagination as PaginationLowCode};
2.While dragging and dropping the Pagination component without wrapping the themeProvider i get the below console error and the code goes into PaginationItem.js file -
Current behavior
Component breaks if not having the ThemeProvider as a parent.
Expected behavior
Component shouldn't break even if the ThemeProvider is not present as parent.
Context
No response
Your environment
npx @mui/envinfo
Search keywords: Pagination
The text was updated successfully, but these errors were encountered: