Overwrite Material UI prop types - reactjs

I'm using React, Typescript, and Material UI. I'm using createMuiTheme.props to disable ripple for the ListItem component globally like this:
createMuiTheme({
props: {
MuiListItem: {
disableRipple: true,
disableTouchRipple: true,
disableFocusRibble: true
}
}
})
But Typescript complains that:
Types of property 'MuiListItem' are incompatible.
Type '{ disableRipple: boolean; disableTouchRipple: boolean; disableFocusRibble: boolean; }' has no properties in common with type 'Partial<OverrideProps<ListItemTypeMap<{}, "li">, "li">>'.ts(2322)
So I created a types.d.ts file in the project root and added the following code:
import { ListItemProps as PrevListItemProps } from "#material-ui/core/ListItem";
import { ButtonBaseProps } from "#material-ui/core/ButtonBase";
declare module "#material-ui/core/ListItem" {
export type ListItemProps = PrevListItemProps & ButtonBaseProps;
}
Which fixes the previous issue but now Typescripts errors because:
ListItem.d.ts(50, 13): 'ListItemProps' was also declared here.
Any idea how to fix this? Or disable ripple for ListItem without passing it each time to components?
Thanks!

You can disable ripple effect globally for all buttons:
https://material-ui.com/ru/getting-started/faq/
import { createMuiTheme } from '#material-ui/core'
const theme = createMuiTheme({
props: {
MuiButtonBase: {
disableRipple: true,
},
},
})
Or you can create your own component:
import ListItem from '#material-ui/core/ListItem'
const CustomListItem = props => <ListItem {...props} button disableRipple disableTouchRipple />

Related

Extend MUI components from theme provider

Currently I'm wondering about if there is the possibility of extending components, by adding new props directly from the theme provider.
For example, let's take the IconButton component, I want to add square prop to this component
import { Components, Theme } from '#mui/material';
export const MuiIconButton: Components<Theme>['MuiIconButton'] = {
defaultProps: {
square: true
},
styleOverrides: {
root: ({ ownerState }) => ({
//here I would like to access the square prop
borderRadius: ownerState.square ? 0 : 50,
})
}
};
declare module '#mui/material/IconButton' {
interface IconButtonPropsOverrides {
square: boolean;
}
}
By taking a look into IconButton.d.ts from MUI,
export interface IconButtonPropsColorOverrides {}
export interface IconButtonPropsSizeOverrides {}
There is no override for props available...
My question is if there is any possibility of adding this override without having to alter the MUI code base. Is there a general approach over this?
Thanks

Typescript validation issue when using Storybook with MUI

I have an Typescript validation issue when trying to pass args as children to a MUI button documented in Storybook :-(
Any ideas how I can pass this as children and not get a Typescript error? I assume it's unhappy as its not a ReactNode. TIA
The default Mui Button doesn't have a label property.
https://mui.com/material-ui/api/button/
You need to extend the Mui Button Types. You can do something like:
import {
ButtonProps as MuiButtonProps,
} from '#mui/material/Button';
interface ButtonPropsOverrides {
label?: string
}
export type ButtonProps = MuiButtonProps & ButtonPropsOverrides;
Or do it like intended by Mui:
export default {
title: 'Atoms',
component: Button,
args: {
children: 'Label',
},
} as ComponentMeta<Shape>;
const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />;
Because the Mui Button is using children as the actual label.

TS2739: Unable to consume custom Tippy wrapper extending TippyProps in typescript

We maintain two separate repositories as library. Both are using reactjs. One is pure component library while other contains sharable modules.
I started integrating typescript in both these libraries.
Here is Tippy wrapper naming Tippy.tsx in component library.
import Tooltip, {TippyProps} from '#tippyjs/react'
interface TippyType extends TippyProps {
hook: string;
style: Object;
}
const Tippy:React.FC<TippyType> = (props) => {
const {dataHook = '', style = {}} = props
function onCreate (instance: any) {
props?.onCreate?.(instance)
if (dataHook) {
instance.props.content.setAttribute('data-hook', dataHook)
}
Object.entries(style).forEach(([property, value]) => {
content.style[property] = value
})
}
return (
<Tooltip
{ ...props}
onCreate={onCreate}
>
{props.children}
</Tooltip>
)
}
export default Tippy
This code builds successfully. But when I try to use this component in module library, typescript only acknowledges hook and style props. All other props from tippy PropTypes throw error.
e.g. following code
<Tippy
content={value}
theme='material'
>
<span className='inline-block m-r-5 to-ellipsis overflow-hidden ws-nowrap'>{value}</span>
</Tippy>
throws
TS2739: Type '{ children: Element; content: string; theme: string; }' is missing the following properties from type 'TippyType': hook, 'style'
Here is the declaration file automatically generated tippy.d.ts
import { TippyProps } from '#tippyjs/react';
import React from 'react';
import './styles.scss';
import 'tippy.js/dist/tippy.css';
interface TippyType extends TippyProps {
hook: string;
'style': Object;
}
declare const Tippy: React.FC<TippyType>;
export default Tippy;
Here is TippyProps
TS2739: Type '{ children: Element; content: string; theme: string; }' is missing the following properties from type 'TippyType': hook, 'style'
The error is warning you hook and style are compulsory in Tippy Component.
interface TippyType extends TippyProps {
hook: string; // <--- compulsory
style: Object; // <--- compulsory
}
Therefore, you need to pass hook and style when using Tippy.
<Tippy
hook=""
style={{}}
content={value}
theme='material'
>
<span className='inline-block m-r-5 to-ellipsis overflow-hidden ws-nowrap'>{value}</span>
</Tippy>
If you want to mark hook and style as optional, use ?:
interface TippyType extends TippyProps {
hook?: string;
style?: Object;
}

How can I add a global control matcher in Storybook?

I am building a component library in React and TypeScript using Storybook. Many components have an icon prop. In the code snippet below, you can see a Component story example where I customize the icon prop's control using a select type with icon options.
// Component.stories.js
import { Component } from './component';
import { iconOptions, DefaultIcon } from "./icons";
export default {
component: Component,
title: 'Component',
argTypes: {
icon: {
control: {
type: 'select'
},
options: iconOptions,
defaultValue: DefaultIcon
}
}
};
The problem is that this setup is repetitive for all components using icon prop. Instead, I would like to configure this globally for all components. So any prop called icon would automatically get a select control with icon options.
I tried editing the .storybook/preview.js file:
export const parameters = {
controls: {
icon: {
control: {
type: 'select'
},
options: iconOptions,
defaultValue: DefaultIcon,
}
}
};
However, that did not work.
How can I configure such a global control?

Adding custom colors to palette gives Object is possibly 'undefined'. TS2532

Im trying to add new custom colors to material-ui palette (i know its coming with 4.1 but thats are bit out in the future)
I'm new with typescript so I have a hard time figuring out what to do to make it work
I have followed the guide from amterial-ui's documentation https://material-ui.com/guides/typescript/#customization-of-theme and came up with this
import createMuiTheme, { ThemeOptions } from '#material-ui/core/styles/createMuiTheme';
declare module '#material-ui/core/styles/createPalette' {
interface Palette {
warning?: PaletteColor
success?: PaletteColor
}
interface PaletteOptions {
warning?: PaletteColorOptions
success?: PaletteColorOptions
}
}
export default function createMyTheme(options: ThemeOptions) {
return createMuiTheme({
...options,
})
}
and when using it
import createStyles from '#material-ui/core/styles/createStyles';
import { Theme } from '#material-ui/core/styles/createMuiTheme';
const styles = (theme: Theme) => createStyles({
success: {
backgroundColor: theme.palette.success.main,
},
error: {
backgroundColor: theme.palette.error.dark,
},
info: {
backgroundColor: theme.palette.primary.dark,
},
warning: {
backgroundColor: theme.palette.warning.main,
},
});
connected to the component with the withStyles HOC
All i get is this error in the console
Object is possibly 'undefined'. TS2532
pointing to backgroundColor: theme.palette.success.main,
Has anyone made this work?
You don't have to make Palette properties optional - it is assumed that they will have some default values, if not overridden by options. Change it's description to the following:
interface Palette {
warning: PaletteColor
success: PaletteColor
}
And all should work fine.

Resources