Skip to content

Commit

Permalink
[system] Add useThemeProps & useTheme hooks (#26649)
Browse files Browse the repository at this point in the history
  • Loading branch information
mnajdova authored Jun 11, 2021
1 parent 925c984 commit 39379db
Show file tree
Hide file tree
Showing 19 changed files with 118 additions and 30 deletions.
1 change: 1 addition & 0 deletions packages/material-ui-system/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
},
"dependencies": {
"@babel/runtime": "^7.4.4",
"@material-ui/private-theming": "5.0.0-alpha.35",
"@material-ui/styled-engine": "5.0.0-alpha.34",
"@material-ui/types": "6.0.1",
"@material-ui/utils": "5.0.0-alpha.35",
Expand Down
2 changes: 1 addition & 1 deletion packages/material-ui-system/src/colorManipulator.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ export function emphasize(color, coefficient = 0.15) {
}

/**
* Set the absolute transparency of a color.
* Sets the absolute transparency of a color.
* Any existing alpha values are overwritten.
* @param {string} color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color()
* @param {number} value - value to set the alpha channel to in the range 0 - 1
Expand Down
17 changes: 3 additions & 14 deletions packages/material-ui-system/src/createBox.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import styled, { ThemeContext } from '@material-ui/styled-engine';
import styled from '@material-ui/styled-engine';
import styleFunctionSx, { extendSxProp } from './styleFunctionSx';
import createTheme from './createTheme';
import useTheme from './useTheme';

function isObjectEmpty(obj) {
return Object.keys(obj).length === 0;
}

const useTheme = (defaultTheme) => {
const contextTheme = React.useContext(ThemeContext);
return !contextTheme || isObjectEmpty(contextTheme) ? defaultTheme : contextTheme;
};

export const systemDefaultTheme = createTheme();

export default function createBox(defaultTheme = systemDefaultTheme) {
export default function createBox(defaultTheme) {
const BoxRoot = styled('div')(styleFunctionSx);

const Box = React.forwardRef(function Box(inProps, ref) {
Expand Down
6 changes: 6 additions & 0 deletions packages/material-ui-system/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,10 @@ export { SpacingOptions, Spacing } from './createTheme/createSpacing';
export { default as shape } from './createTheme/shape';
export * from './createTheme/shape';

export { default as unstable_useThemeProps } from './useThemeProps';
export { getThemeProps as unstable_getThemeProps } from './useThemeProps';

export { default as useTheme } from './useTheme';
export * from './useTheme';

export * from './colorManipulator';
3 changes: 3 additions & 0 deletions packages/material-ui-system/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,7 @@ export { default as styled } from './styled';
export { default as createTheme } from './createTheme';
export { default as createBreakpoints } from './createTheme/createBreakpoints';
export { default as shape } from './createTheme/shape';
export { default as unstable_useThemeProps } from './useThemeProps';
export { getThemeProps as unstable_getThemeProps } from './useThemeProps';
export { default as useTheme } from './useTheme';
export * from './colorManipulator';
3 changes: 3 additions & 0 deletions packages/material-ui-system/src/useTheme.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Theme } from './createTheme';

export default function useTheme<T = Theme>(defaultTheme?: T): T;
19 changes: 19 additions & 0 deletions packages/material-ui-system/src/useTheme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as React from 'react';
import { useTheme as muiUseTheme } from '@material-ui/private-theming';
import { ThemeContext } from '@material-ui/styled-engine';
import createTheme from './createTheme';

function isObjectEmpty(obj) {
return Object.keys(obj).length === 0;
}

export const systemDefaultTheme = createTheme();

function useTheme(defaultTheme = systemDefaultTheme) {
const muiContextTheme = muiUseTheme();
const styledEngineContextTheme = React.useContext(ThemeContext);
const contextTheme = muiContextTheme || styledEngineContextTheme;
return !contextTheme || isObjectEmpty(contextTheme) ? defaultTheme : contextTheme;
}

export default useTheme;
4 changes: 4 additions & 0 deletions packages/material-ui-system/src/useThemeProps/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { default } from './useThemeProps';
export * from './useThemeProps';

export { default as getThemeProps } from './getThemeProps';
2 changes: 2 additions & 0 deletions packages/material-ui-system/src/useThemeProps/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './useThemeProps';
export { default as getThemeProps } from './getThemeProps';
24 changes: 24 additions & 0 deletions packages/material-ui-system/src/useThemeProps/useThemeProps.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export interface ThemeWithProps {
components?: any;
}

export type ThemedProps<Theme, Name extends keyof any> = Theme extends {
components: Record<Name, { defaultProps: infer Props }>;
}
? Props
: {};

export interface AdditionalThemeProps<Theme> {
isRtl: boolean;
theme: Theme;
}

export default function useThemeProps<
Theme extends ThemeWithProps,
Props,
Name extends keyof any,
>(params: {
props: Props;
name: Name;
defaultTheme?: Theme;
}): Props & ThemedProps<Theme, Name> & AdditionalThemeProps<Theme>;
14 changes: 14 additions & 0 deletions packages/material-ui-system/src/useThemeProps/useThemeProps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import getThemeProps from './getThemeProps';
import useTheme from '../useTheme';

export default function useThemeProps({ props, name, defaultTheme }) {
const contextTheme = useTheme(defaultTheme);
const more = getThemeProps({ theme: contextTheme, name, props });
const theme = more.theme || contextTheme;

return {
theme,
isRtl: theme.direction === 'rtl',
...more,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { unstable_useThemeProps as useThemeProps } from '@material-ui/system';
import { expectType } from '@material-ui/types';

interface SliderProps {
track?: boolean;
valueLabelDisplay?: boolean;
color: 'primary' | 'secondary';
}

interface Theme {
components?: {
MuiSlider: {
defaultProps: SliderProps;
};
};
}

function ThemedComponent() {
const props = useThemeProps<Theme, SliderProps, 'MuiSlider'>({
props: { color: 'primary' },
name: 'MuiSlider',
});

// additional props are valid
expectType<boolean, typeof props.isRtl>(props.isRtl);
expectType<Theme, typeof props.theme>(props.theme);

// component's props are valid
// Only existence of props is relevant here not type.
props.track;
props.valueLabelDisplay;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { elementTypeAcceptingRef } from '@material-ui/utils';
import getThemeProps from '../styles/getThemeProps';
import { unstable_getThemeProps as getThemeProps } from '@material-ui/system';
import Drawer, { getAnchor, isHorizontal } from '../Drawer/Drawer';
import ownerDocument from '../utils/ownerDocument';
import ownerWindow from '../utils/ownerWindow';
Expand Down
4 changes: 2 additions & 2 deletions packages/material-ui/src/styles/useTheme.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useTheme as useThemeWithoutDefault } from '@material-ui/private-theming';
import { useTheme as useThemeSystem } from '@material-ui/system';
import * as React from 'react';
import defaultTheme from './defaultTheme';

export default function useTheme() {
const theme = useThemeWithoutDefault() || defaultTheme;
const theme = useThemeSystem(defaultTheme);

if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line react-hooks/rules-of-hooks
Expand Down
13 changes: 2 additions & 11 deletions packages/material-ui/src/styles/useThemeProps.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
import getThemeProps from './getThemeProps';
import useTheme from './useTheme';
import { unstable_useThemeProps as systemUseThemeProps } from '@material-ui/system';
import defaultTheme from './defaultTheme';

export default function useThemeProps({ props, name }) {
const contextTheme = useTheme() || defaultTheme;
const more = getThemeProps({ theme: contextTheme, name, props });
const theme = more.theme || contextTheme;

return {
theme,
isRtl: theme.direction === 'rtl',
...more,
};
return systemUseThemeProps({ props, name, defaultTheme });
}
2 changes: 1 addition & 1 deletion packages/material-ui/src/useMediaQuery/useMediaQuery.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { useTheme } from '@material-ui/private-theming';
import getThemeProps from '../styles/getThemeProps';
import { unstable_getThemeProps as getThemeProps } from '@material-ui/system';
import useEnhancedEffect from '../utils/useEnhancedEffect';

export default function useMediaQuery(queryInput, options = {}) {
Expand Down

0 comments on commit 39379db

Please sign in to comment.