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

[core] Adds component prop to OverrideProps type #35924

Merged
merged 24 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/data/material/guides/routing/LinkRouterWithTheme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const theme = createTheme({
MuiLink: {
defaultProps: {
component: LinkBehavior,
} as LinkProps,
} as unknown as LinkProps,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unfortunate. We shouldn't recommend such hacks, ideally, but I understand where it's coming from. Could ou try to work around it so such an ugly cast is not necessary?

Copy link
Contributor Author

@sai6855 sai6855 Apr 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i've tried to remove as unknown type without disturbing other files but couldn't able to do it. So instead of fixing casting problem, tried to fix (commit 089f989 ) the root problem which lies in this file .

If you are fine with converting props in props.d.ts file to generic, i'll convert all components to generic where applicable. if not i'd appreciate your help fixing the casting issue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd ask @mnajdova about the generic, as she's overseeing the styles. To me, it feels OK, but I have less context about the usage of these types.

},
MuiButtonBase: {
defaultProps: {
Expand Down
2 changes: 1 addition & 1 deletion docs/src/modules/components/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export type LinkProps = {
linkAs?: NextLinkProps['as']; // Useful when the as prop is shallow by styled().
noLinkStyle?: boolean;
} & Omit<NextLinkComposedProps, 'to' | 'linkAs' | 'href'> &
Omit<MuiLinkProps, 'href'>;
Omit<MuiLinkProps, 'href' | 'component'>;
ZeeshanTamboli marked this conversation as resolved.
Show resolved Hide resolved

// A styled version of the Next.js Link component:
// https://nextjs.org/docs/api-reference/next/link
Expand Down
4 changes: 2 additions & 2 deletions packages/mui-material/src/AppBar/AppBar.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { SxProps } from '@mui/system';
import { DistributiveOmit, OverridableStringUnion } from '@mui/types';
import { OverridableComponent, OverrideProps } from '@mui/material/OverridableComponent';
import { PropTypes, Theme } from '..';
import { PaperProps } from '../Paper';
import { PaperBaseProps } from '../Paper';
import { AppBarClasses } from './appBarClasses';

export interface AppBarPropsColorOverrides {}

export interface AppBarTypeMap<P = {}, D extends React.ElementType = 'header'> {
props: P &
DistributiveOmit<PaperProps, 'position' | 'color' | 'classes'> & {
DistributiveOmit<PaperBaseProps, 'position' | 'color' | 'classes'> & {
/**
* Override or extend the styles applied to the component.
*/
Expand Down
14 changes: 13 additions & 1 deletion packages/mui-material/src/AppBar/AppBar.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import AppBar from '@mui/material/AppBar';
import { expectType } from '@mui/types';

const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> =
function CustomComponent() {
Expand All @@ -12,7 +13,18 @@ function AppBarTest() {
<AppBar />
<AppBar elevation={4} />

<AppBar component="a" href="test" />
<AppBar
onClick={(event) => {
expectType<React.MouseEvent<HTMLElement, MouseEvent>, typeof event>(event);
}}
/>
<AppBar
component="a"
href="test"
onClick={(event) => {
expectType<React.MouseEvent<HTMLAnchorElement, MouseEvent>, typeof event>(event);
}}
/>
<AppBar component={CustomComponent} stringProp="test" numberProp={0} />
{/* @ts-expect-error missing stringProp and numberProp */}
<AppBar component={CustomComponent} />
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-material/src/Button/Button.js
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ Button.propTypes /* remove-proptypes */ = {
* The component used for the root node.
* Either a string to use a HTML element or a component.
*/
component: PropTypes.elementType,
component: PropTypes /* @typescript-to-proptypes-ignore */.elementType,
/**
* If `true`, the component is disabled.
* @default false
Expand Down
33 changes: 33 additions & 0 deletions packages/mui-material/src/Button/Button.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,39 @@ function FakeIcon() {
return <div>Icon</div>;
}

const props1: ButtonProps<'div'> = {
component: 'div',
onChange: (event) => {
expectType<React.FormEvent<HTMLDivElement>, typeof event>(event);
},
};

const props2: ButtonProps = {
onChange: (event) => {
expectType<React.FormEvent<HTMLButtonElement>, typeof event>(event);
},
};

const props3: ButtonProps<'span'> = {
// @ts-expect-error
component: 'div',
};

const props4: ButtonProps<typeof TestOverride> = {
component: TestOverride,
x: 2,
};

const props5: ButtonProps<typeof TestOverride> = {
component: TestOverride,
// @ts-expect-error
inCorrectProp: 3,
};

const props6: ButtonProps<typeof TestOverride> = {
component: TestOverride,
};

const buttonTest = () => (
<div>
<Button>I am a button!</Button>
Expand Down
4 changes: 2 additions & 2 deletions packages/mui-material/src/Card/Card.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { SxProps } from '@mui/system';
import { DistributiveOmit } from '@mui/types';
import { OverridableComponent, OverrideProps } from '@mui/material/OverridableComponent';
import { Theme } from '..';
import { PaperProps } from '../Paper';
import { PaperBaseProps } from '../Paper';
import { CardClasses } from './cardClasses';

// TODO: v6 remove this interface, it is not used
export interface CardPropsColorOverrides {}

export interface CardTypeMap<P = {}, D extends React.ElementType = 'div'> {
props: P &
DistributiveOmit<PaperProps, 'classes'> & {
DistributiveOmit<PaperBaseProps, 'classes'> & {
/**
* Override or extend the styles applied to the component.
*/
Expand Down
33 changes: 33 additions & 0 deletions packages/mui-material/src/Card/Card.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as React from 'react';
import Card from '@mui/material/Card';
import { expectType } from '@mui/types';

const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> =
function CustomComponent() {
return <div />;
};

function CardTest() {
return (
<div>
<Card />
<Card elevation={4} />
<Card
onClick={(event) => {
expectType<React.MouseEvent<HTMLDivElement, MouseEvent>, typeof event>(event);
}}
/>
<Card
component="a"
href="test"
onClick={(event) => {
expectType<React.MouseEvent<HTMLAnchorElement, MouseEvent>, typeof event>(event);
}}
/>

<Card component={CustomComponent} stringProp="test" numberProp={0} />
{/* @ts-expect-error missing stringProp and numberProp */}
<Card component={CustomComponent} />
</div>
);
}
13 changes: 9 additions & 4 deletions packages/mui-material/src/CardHeader/CardHeader.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,23 @@ interface ComponentProp {
component?: React.ElementType;
}

<CardHeader component={CustomComponent} stringProp="s" numberProp={2} />;

function createElementBasePropMixedTest() {
React.createElement<CardHeaderProps<DefaultComponent, ComponentProp>>(CardHeader);
React.createElement<CardHeaderProps<DefaultComponent, ComponentProp>>(CardHeader, {
component: 'div',
});
// ExpectError: type system should be demanding the required props of "CustomComponent"
React.createElement<CardHeaderProps<DefaultComponent, ComponentProp>>(CardHeader, {
// @ts-expect-error
React.createElement<CardHeaderProps<typeof CustomComponent>>(CardHeader, {
component: CustomComponent,
stringProp: '2',
numberProp: 3,
incorrectProp: 3,
});
// @ts-expect-error
React.createElement<CardHeaderProps<DefaultComponent, ComponentProp>>(CardHeader, {
// This test shouldn't fail but does; stringProp & numberProp are required props of CustomComponent

React.createElement<CardHeaderProps<typeof CustomComponent>>(CardHeader, {
component: CustomComponent,
stringProp: '',
numberProp: 0,
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-material/src/Dialog/Dialog.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export interface DialogProps extends StandardProps<ModalProps, 'children'> {
* Props applied to the [`Paper`](/material-ui/api/paper/) element.
* @default {}
*/
PaperProps?: Partial<PaperProps>;
PaperProps?: Partial<PaperProps<React.ElementType>>;
/**
* Determine the container for scrolling the dialog.
* @default 'paper'
Expand Down
18 changes: 15 additions & 3 deletions packages/mui-material/src/Dialog/Dialog.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import * as React from 'react';
import { Dialog } from '@mui/material';
import { Dialog, PaperProps } from '@mui/material';
ZeeshanTamboli marked this conversation as resolved.
Show resolved Hide resolved
import { expectType } from '@mui/types';

function optionalChildrenTest() {
<Dialog open />;
const paperProps: PaperProps<'span'> = {
component: 'span',
onClick: (event) => {
expectType<React.MouseEvent<HTMLSpanElement, MouseEvent>, typeof event>(event);
},
};
function Test() {
return (
<React.Fragment>
<Dialog open />;
<Dialog open PaperProps={paperProps} />;
</React.Fragment>
);
}
2 changes: 1 addition & 1 deletion packages/mui-material/src/Drawer/Drawer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export interface DrawerProps extends StandardProps<ModalProps, 'open' | 'childre
* Props applied to the [`Paper`](/material-ui/api/paper/) element.
* @default {}
*/
PaperProps?: Partial<PaperProps>;
PaperProps?: Partial<PaperProps<React.ElementType>>;
/**
* Props applied to the [`Slide`](/material-ui/api/slide/) element.
*/
Expand Down
18 changes: 18 additions & 0 deletions packages/mui-material/src/Drawer/Drawer.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from 'react';
import { Drawer, PaperProps } from '@mui/material';
ZeeshanTamboli marked this conversation as resolved.
Show resolved Hide resolved
import { expectType } from '@mui/types';

const paperProps: PaperProps<'span'> = {
component: 'span',
onClick: (event) => {
expectType<React.MouseEvent<HTMLSpanElement, MouseEvent>, typeof event>(event);
},
};
function Test() {
return (
<React.Fragment>
<Drawer open />;
<Drawer open PaperProps={paperProps} />;
</React.Fragment>
);
}
2 changes: 1 addition & 1 deletion packages/mui-material/src/Fab/Fab.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ Fab.propTypes /* remove-proptypes */ = {
* The component used for the root node.
* Either a string to use a HTML element or a component.
*/
component: PropTypes.elementType,
component: PropTypes /* @typescript-to-proptypes-ignore */.elementType,
/**
* If `true`, the component is disabled.
* @default false
Expand Down
66 changes: 66 additions & 0 deletions packages/mui-material/src/FormHelperText/FormHelperText.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import * as React from 'react';
import FormHelperText, { FormHelperTextProps } from '@mui/material/FormHelperText';
import { expectType } from '@mui/types';

const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> =
function CustomComponent() {
return <div />;
};

const props: FormHelperTextProps<'div'> = {
component: 'div',
onChange: (event) => {
expectType<React.FormEvent<HTMLDivElement>, typeof event>(event);
},
};

const props2: FormHelperTextProps = {
onChange: (event) => {
expectType<React.FormEvent<HTMLParagraphElement>, typeof event>(event);
},
};

const props3: FormHelperTextProps<'span'> = {
// @ts-expect-error
component: 'div',
};

const props4: FormHelperTextProps<typeof CustomComponent> = {
component: CustomComponent,
stringProp: '2',
numberProp: 2,
};

const props5: FormHelperTextProps<typeof CustomComponent> = {
component: CustomComponent,
stringProp: '2',
numberProp: 2,
// @ts-expect-error
inCorrectProp: 3,
};

// @ts-expect-error
const props6: FormHelperTextProps<typeof CustomComponent> = {
component: CustomComponent,
};

const TestComponent = () => {
return (
<React.Fragment>
<FormHelperText />
<FormHelperText component={'a'} href="/test" />

<FormHelperText component={CustomComponent} stringProp="s" numberProp={1} />
{
// @ts-expect-error
<FormHelperText component={CustomComponent} />
}
<FormHelperText
component="span"
onChange={(event) => {
expectType<React.FormEvent<HTMLSpanElement>, typeof event>(event);
}}
/>
</React.Fragment>
);
};
65 changes: 63 additions & 2 deletions packages/mui-material/src/Grid/Grid.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,68 @@
import * as React from 'react';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';
import Grid, { GridProps } from '@mui/material/Grid';
import { expectType } from '@mui/types';

const CustomComponent: React.FC<{ stringProp: string; numberProp: number }> =
function CustomComponent() {
return <div />;
};

const props: GridProps<'span'> = {
component: 'span',
onChange: (event) => {
expectType<React.FormEvent<HTMLSpanElement>, typeof event>(event);
},
};

const props2: GridProps = {
onChange: (event) => {
expectType<React.FormEvent<HTMLDivElement>, typeof event>(event);
},
};

const props3: GridProps<'span'> = {
// @ts-expect-error
component: 'div',
};

const props4: GridProps<typeof CustomComponent> = {
component: CustomComponent,
stringProp: '2',
numberProp: 2,
};

const props5: GridProps<typeof CustomComponent> = {
component: CustomComponent,
stringProp: '2',
numberProp: 2,
// @ts-expect-error
inCorrectProp: 3,
};

// @ts-expect-error
const props6: GridProps<typeof CustomComponent> = {
component: CustomComponent,
};

function ResponsiveTest() {
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square />;
return (
<React.Fragment>
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square />
<Grid item component={'a'} href="/test" />

<Grid item component={CustomComponent} stringProp="s" numberProp={1} />
{
// @ts-expect-error
<Grid item component={CustomComponent} />
}
<Grid
item
component="span"
onChange={(event) => {
expectType<React.FormEvent<HTMLSpanElement>, typeof event>(event);
}}
/>
</React.Fragment>
);
}
Loading