(
- styles: StyleRules,
-): StyleRules
;
+export default function createStyles(
+ styles: StyleRules,
+): StyleRules;
diff --git a/packages/material-ui-styles/src/styled/styled.d.ts b/packages/material-ui-styles/src/styled/styled.d.ts
index 73068b41f70ab6..c0be94321bc2e0 100644
--- a/packages/material-ui-styles/src/styled/styled.d.ts
+++ b/packages/material-ui-styles/src/styled/styled.d.ts
@@ -1,6 +1,6 @@
import { Omit } from '@material-ui/types';
import {
- CSSProperties,
+ CreateCSSProperties,
StyledComponentProps,
WithStylesOptions,
} from '@material-ui/styles/withStyles';
@@ -9,11 +9,16 @@ import * as React from 'react';
/**
* @internal
*/
-export type ComponentCreator = (
- styles: CSSProperties | (({ theme, ...props }: { theme: Theme } & Props) => CSSProperties),
+export type ComponentCreator = (
+ styles:
+ | CreateCSSProperties
+ | (({ theme, ...props }: { theme: Theme } & Props) => CreateCSSProperties),
options?: WithStylesOptions,
) => React.ComponentType<
- Omit>, 'classes' | 'className'> &
+ Omit<
+ JSX.LibraryManagedAttributes>,
+ 'classes' | 'className'
+ > &
StyledComponentProps<'root'> & { className?: string }
>;
@@ -21,4 +26,6 @@ export interface StyledProps {
className: string;
}
-export default function styled(Component: C): ComponentCreator;
+export default function styled(
+ Component: Component,
+): ComponentCreator;
diff --git a/packages/material-ui-styles/src/withStyles/withStyles.d.ts b/packages/material-ui-styles/src/withStyles/withStyles.d.ts
index a491421267be14..5111f4c9ef292a 100644
--- a/packages/material-ui-styles/src/withStyles/withStyles.d.ts
+++ b/packages/material-ui-styles/src/withStyles/withStyles.d.ts
@@ -8,6 +8,20 @@ export interface CSSProperties extends CSS.Properties {
[k: string]: CSS.Properties[keyof CSS.Properties] | CSSProperties;
}
+export type BaseCreateCSSProperties = {
+ [P in keyof CSS.Properties]:
+ | CSS.Properties[P]
+ | ((props: Props) => CSS.Properties[P])
+};
+
+export interface CreateCSSProperties
+ extends BaseCreateCSSProperties {
+ // Allow pseudo selectors and media queries
+ [k: string]:
+ | BaseCreateCSSProperties[keyof BaseCreateCSSProperties]
+ | CreateCSSProperties;
+}
+
/**
* This is basically the API of JSS. It defines a Map,
* where
@@ -16,9 +30,9 @@ export interface CSSProperties extends CSS.Properties {
*
* if only `CSSProperties` are matched `Props` are inferred to `any`
*/
-export type StyleRules = Record<
+export type StyleRules = Record<
ClassKey,
- CSSProperties | ((props: Props) => CSSProperties)
+ CreateCSSProperties | ((props: Props) => CreateCSSProperties)
>;
/**
@@ -28,7 +42,7 @@ export type StyleRulesCallback StyleRules;
-export type Styles =
+export type Styles =
| StyleRules
| StyleRulesCallback;
@@ -44,31 +58,31 @@ export type ClassNameMap = Record = string | Styles;
-export type ClassKeyOfStyles = S extends string
- ? S
- : S extends StyleRulesCallback
- ? K
- : S extends StyleRules
- ? K
+export type ClassKeyInferable = string | Styles;
+export type ClassKeyOfStyles = StylesOrClassKey extends string
+ ? StylesOrClassKey
+ : StylesOrClassKey extends StyleRulesCallback
+ ? ClassKey
+ : StylesOrClassKey extends StyleRules
+ ? ClassKey
: never;
/**
* infers the type of the theme used in the styles
*/
-export type PropsOfStyles = S extends Styles ? Props : {};
+export type PropsOfStyles = StylesType extends Styles ? Props : {};
/**
* infers the type of the props used in the styles
*/
-export type ThemeOfStyles = S extends Styles ? Theme : {};
+export type ThemeOfStyles = StylesType extends Styles ? Theme : {};
export type WithStyles<
- S extends ClassKeyInferable,
+ StylesType extends ClassKeyInferable,
IncludeTheme extends boolean | undefined = false
-> = (IncludeTheme extends true ? { theme: ThemeOfStyles } : {}) & {
- classes: ClassNameMap>;
+> = (IncludeTheme extends true ? { theme: ThemeOfStyles } : {}) & {
+ classes: ClassNameMap>;
innerRef?: React.Ref | React.RefObject;
-} & PropsOfStyles;
+} & PropsOfStyles;
export interface StyledComponentProps {
classes?: Partial>;
@@ -76,9 +90,12 @@ export interface StyledComponentProps {
}
export default function withStyles<
- S extends Styles,
- Options extends WithStylesOptions> = {}
+ StylesType extends Styles,
+ Options extends WithStylesOptions> = {}
>(
- style: S,
+ style: StylesType,
options?: Options,
-): PropInjector, StyledComponentProps>>;
+): PropInjector<
+ WithStyles,
+ StyledComponentProps>
+>;
diff --git a/packages/material-ui-styles/test/styles.spec.tsx b/packages/material-ui-styles/test/styles.spec.tsx
index 237a8565447154..bdd03816e14013 100644
--- a/packages/material-ui-styles/test/styles.spec.tsx
+++ b/packages/material-ui-styles/test/styles.spec.tsx
@@ -1,5 +1,12 @@
import * as React from 'react';
-import { createStyles, withStyles, withTheme, WithTheme, WithStyles } from '@material-ui/styles';
+import {
+ createStyles,
+ withStyles,
+ withTheme,
+ WithTheme,
+ WithStyles,
+ makeStyles,
+} from '@material-ui/styles';
import Button from '@material-ui/core/Button';
import { Theme } from '@material-ui/core/styles';
@@ -419,3 +426,26 @@ function forwardRefTest() {
// especially since `innerRef` will be removed in v5 and is equivalent to `ref`
;
}
+
+{
+ // https://github.com/mui-org/material-ui/pull/15546
+ // Update type definition to let CSS properties be functions
+ interface testProps {
+ foo: boolean;
+ }
+ const useStyles = makeStyles((theme: Theme) => ({
+ root: {
+ width: (prop: testProps) => (prop.foo ? 100 : 0),
+ },
+ root2: (prop2: testProps) => ({
+ width: (prop: testProps) => (prop.foo && prop2.foo ? 100 : 0),
+ height: 100,
+ }),
+ }));
+
+ const styles = useStyles({ foo: true });
+ // $ExpectType string
+ const root = styles.root;
+ // $ExpectType string
+ const root2 = styles.root2;
+}
diff --git a/packages/material-ui/src/styles/createStyles.d.ts b/packages/material-ui/src/styles/createStyles.d.ts
index 427c1f555f9099..99f966d4dc1a0d 100644
--- a/packages/material-ui/src/styles/createStyles.d.ts
+++ b/packages/material-ui/src/styles/createStyles.d.ts
@@ -1,11 +1,3 @@
-import { StyleRules } from './withStyles';
+import createStyles from '@material-ui/styles/createStyles';
-/**
- * This function doesn't really "do anything" at runtime, it's just the identity
- * function. Its only purpose is to defeat TypeScript's type widening when providing
- * style rules to `withStyles` which are a function of the `Theme`.
- *
- * @param styles a set of style mappings
- * @returns the same styles that were passed in
- */
-export default function createStyles(styles: StyleRules): StyleRules;
+export default createStyles;
diff --git a/packages/material-ui/src/styles/withStyles.d.ts b/packages/material-ui/src/styles/withStyles.d.ts
index ee0a8546b0914b..451f0c96663275 100644
--- a/packages/material-ui/src/styles/withStyles.d.ts
+++ b/packages/material-ui/src/styles/withStyles.d.ts
@@ -1,55 +1,48 @@
-import * as React from 'react';
-import { CSSProperties, WithStylesOptions } from '@material-ui/styles/withStyles';
import { PropInjector } from '@material-ui/types';
import { Theme } from './createMuiTheme';
-
-export { CSSProperties, WithStylesOptions };
+import {
+ CreateCSSProperties,
+ CSSProperties,
+ ClassNameMap,
+ StyledComponentProps,
+ WithStylesOptions,
+ StyleRules as ActualStyleRules,
+ StyleRulesCallback,
+ Styles,
+ ClassKeyOfStyles,
+} from '@material-ui/styles/withStyles';
+
+export {
+ CreateCSSProperties,
+ CSSProperties,
+ ClassNameMap,
+ StyledComponentProps,
+ Styles,
+ WithStylesOptions,
+ StyleRulesCallback,
+};
/**
- * This is basically the API of JSS. It defines a Map,
- * where
- *
- * - the `keys` are the class (names) that will be created
- * - the `values` are objects that represent CSS rules (`React.CSSProperties`).
+ * Adapter for `StyleRules` from `@material-ui/styles` for backwards compatibility.
+ * Order of generic arguments is just reversed.
*/
-export type StyleRules = Record;
-
-export type StyleRulesCallback = (
- theme: Theme,
-) => StyleRules;
-
-export interface StylesCreator {
- create(theme: Theme, name: string): StyleRules;
- options: { index: number };
- themingEnabled: boolean;
-}
-
-export type ClassNameMap = Record;
+export type StyleRules<
+ ClassKey extends string = string,
+ Props extends object = {}
+> = ActualStyleRules;
export type WithStyles<
- T extends string | StyleRules | StyleRulesCallback = string,
+ StylesOrClassKey extends string | Styles = string,
IncludeTheme extends boolean | undefined = false
> = (IncludeTheme extends true ? { theme: Theme } : {}) & {
- classes: ClassNameMap<
- T extends string
- ? T
- : T extends StyleRulesCallback
- ? K
- : T extends StyleRules
- ? K
- : never
- >;
+ classes: ClassNameMap>;
};
-export interface StyledComponentProps {
- classes?: Partial>;
- innerRef?: React.Ref | React.RefObject;
-}
-
export default function withStyles<
ClassKey extends string,
- Options extends WithStylesOptions = {}
+ Options extends WithStylesOptions = {},
+ Props extends object = {}
>(
- style: StyleRulesCallback | StyleRules,
+ style: Styles,
options?: Options,
): PropInjector, StyledComponentProps>;
diff --git a/packages/material-ui/test/typescript/components.spec.tsx b/packages/material-ui/test/typescript/components.spec.tsx
index 2f30decd0e7ab0..4f5a80add360b1 100644
--- a/packages/material-ui/test/typescript/components.spec.tsx
+++ b/packages/material-ui/test/typescript/components.spec.tsx
@@ -872,7 +872,7 @@ const TabsTest = () => {
type ClassKey = 'root' | 'button';
- const styles: StyleRulesCallback = theme => ({
+ const styles: StyleRulesCallback = theme => ({
root: {
flexGrow: 1,
marginTop: theme.spacing(3),
diff --git a/packages/material-ui/test/typescript/styles.spec.tsx b/packages/material-ui/test/typescript/styles.spec.tsx
index c1b71714d7122f..0585739b6dad16 100644
--- a/packages/material-ui/test/typescript/styles.spec.tsx
+++ b/packages/material-ui/test/typescript/styles.spec.tsx
@@ -264,8 +264,8 @@ withStyles(theme =>
content: {
minHeight: '100vh',
},
+ // $ExpectError
'@media (min-width: 960px)': {
- // $ExpectError
content: {
display: 'flex',
},
@@ -396,7 +396,7 @@ withStyles(theme =>
{
// https://github.com/mui-org/material-ui/issues/11164
- const style: StyleRulesCallback = theme => ({
+ const style: StyleRulesCallback = theme => ({
text: theme.typography.body2,
});
}
@@ -477,3 +477,89 @@ withStyles(theme =>
};
});
}
+
+{
+ // https://github.com/mui-org/material-ui/pull/15546
+ // Update type definition to let CSS properties be functions
+ interface testProps {
+ foo: boolean;
+ }
+
+ // makeStyles accepts properties as functions
+ {
+ const useStyles = makeStyles({
+ root: {
+ width: (prop: testProps) => (prop.foo ? 100 : 0),
+ },
+ root2: (prop2: testProps) => ({
+ width: (prop: testProps) => (prop.foo && prop2.foo ? 100 : 0),
+ }),
+ });
+
+ const styles = useStyles({ foo: true });
+ // $ExpectType string
+ const root = styles.root;
+ // $ExpectType string
+ const root2 = styles.root2;
+ }
+
+ // makeStyles accepts properties as functions using a callback
+ {
+ const useStyles = makeStyles(theme => ({
+ root: {
+ width: (prop: testProps) => (prop.foo ? 100 : 0),
+ },
+ root2: (prop2: testProps) => ({
+ width: (prop: testProps) => (prop.foo && prop2.foo ? 100 : 0),
+ margin: theme.spacing(1),
+ }),
+ }));
+
+ const styles = useStyles({ foo: true });
+ // $ExpectType string
+ const root = styles.root;
+ // $ExpectType string
+ const root2 = styles.root2;
+ }
+
+ // createStyles accepts properties as functions
+ {
+ const styles = createStyles({
+ root: {
+ width: (prop: testProps) => (prop.foo ? 100 : 0),
+ },
+ root2: (prop2: testProps) => ({
+ width: (prop: testProps) => (prop.foo && prop2.foo ? 100 : 0),
+ }),
+ });
+
+ // $ExpectType string
+ const root = makeStyles(styles)({ foo: true }).root;
+ }
+
+ // withStyles accepts properties as functions
+ {
+ withStyles({
+ root: {
+ width: (prop: testProps) => (prop.foo ? 100 : 0),
+ },
+ root2: (prop2: testProps) => ({
+ width: (prop: testProps) => (prop.foo && prop2.foo ? 100 : 0),
+ margin: 8,
+ }),
+ });
+ }
+
+ // withStyles accepts properties as functions using a callback
+ {
+ withStyles(theme => ({
+ root: {
+ width: (prop: testProps) => (prop.foo ? 100 : 0),
+ },
+ root2: (prop2: testProps) => ({
+ width: (prop: testProps) => (prop.foo && prop2.foo ? 100 : 0),
+ height: theme.spacing(1),
+ }),
+ }));
+ }
+}