From 39379dbc4924b9a5e0dcddf8a7e6925c5a9ce7e3 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Fri, 11 Jun 2021 14:17:04 +0200 Subject: [PATCH] [system] Add useThemeProps & useTheme hooks (#26649) --- packages/material-ui-system/package.json | 1 + .../src/colorManipulator.js | 2 +- packages/material-ui-system/src/createBox.js | 17 ++-------- packages/material-ui-system/src/index.d.ts | 6 ++++ packages/material-ui-system/src/index.js | 3 ++ packages/material-ui-system/src/useTheme.d.ts | 3 ++ packages/material-ui-system/src/useTheme.js | 19 +++++++++++ .../src/useThemeProps}/getThemeProps.d.ts | 0 .../src/useThemeProps}/getThemeProps.js | 0 .../src/useThemeProps}/getThemeProps.test.js | 0 .../src/useThemeProps/index.d.ts | 4 +++ .../src/useThemeProps/index.js | 2 ++ .../src/useThemeProps/useThemeProps.d.ts | 24 ++++++++++++++ .../src/useThemeProps/useThemeProps.js | 14 ++++++++ .../src/useThemeProps/useThemeProps.spec.ts | 32 +++++++++++++++++++ .../src/SwipeableDrawer/SwipeableDrawer.js | 2 +- packages/material-ui/src/styles/useTheme.js | 4 +-- .../material-ui/src/styles/useThemeProps.js | 13 ++------ .../src/useMediaQuery/useMediaQuery.js | 2 +- 19 files changed, 118 insertions(+), 30 deletions(-) create mode 100644 packages/material-ui-system/src/useTheme.d.ts create mode 100644 packages/material-ui-system/src/useTheme.js rename packages/{material-ui/src/styles => material-ui-system/src/useThemeProps}/getThemeProps.d.ts (100%) rename packages/{material-ui/src/styles => material-ui-system/src/useThemeProps}/getThemeProps.js (100%) rename packages/{material-ui/src/styles => material-ui-system/src/useThemeProps}/getThemeProps.test.js (100%) create mode 100644 packages/material-ui-system/src/useThemeProps/index.d.ts create mode 100644 packages/material-ui-system/src/useThemeProps/index.js create mode 100644 packages/material-ui-system/src/useThemeProps/useThemeProps.d.ts create mode 100644 packages/material-ui-system/src/useThemeProps/useThemeProps.js create mode 100644 packages/material-ui-system/src/useThemeProps/useThemeProps.spec.ts diff --git a/packages/material-ui-system/package.json b/packages/material-ui-system/package.json index cdcd17f47c8b8c..f0cc8bc1d0b716 100644 --- a/packages/material-ui-system/package.json +++ b/packages/material-ui-system/package.json @@ -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", diff --git a/packages/material-ui-system/src/colorManipulator.js b/packages/material-ui-system/src/colorManipulator.js index 5b750c4151ba20..92add7739a0f92 100644 --- a/packages/material-ui-system/src/colorManipulator.js +++ b/packages/material-ui-system/src/colorManipulator.js @@ -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 diff --git a/packages/material-ui-system/src/createBox.js b/packages/material-ui-system/src/createBox.js index 8d7ca4bccd3ff7..4893579f95164b 100644 --- a/packages/material-ui-system/src/createBox.js +++ b/packages/material-ui-system/src/createBox.js @@ -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) { diff --git a/packages/material-ui-system/src/index.d.ts b/packages/material-ui-system/src/index.d.ts index 7c246c30cbab24..21996bc957885d 100644 --- a/packages/material-ui-system/src/index.d.ts +++ b/packages/material-ui-system/src/index.d.ts @@ -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'; diff --git a/packages/material-ui-system/src/index.js b/packages/material-ui-system/src/index.js index b88bdad6e96c20..7657e10f3b5287 100644 --- a/packages/material-ui-system/src/index.js +++ b/packages/material-ui-system/src/index.js @@ -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'; diff --git a/packages/material-ui-system/src/useTheme.d.ts b/packages/material-ui-system/src/useTheme.d.ts new file mode 100644 index 00000000000000..0c794b641f61dc --- /dev/null +++ b/packages/material-ui-system/src/useTheme.d.ts @@ -0,0 +1,3 @@ +import { Theme } from './createTheme'; + +export default function useTheme(defaultTheme?: T): T; diff --git a/packages/material-ui-system/src/useTheme.js b/packages/material-ui-system/src/useTheme.js new file mode 100644 index 00000000000000..2b1b5992067ff8 --- /dev/null +++ b/packages/material-ui-system/src/useTheme.js @@ -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; diff --git a/packages/material-ui/src/styles/getThemeProps.d.ts b/packages/material-ui-system/src/useThemeProps/getThemeProps.d.ts similarity index 100% rename from packages/material-ui/src/styles/getThemeProps.d.ts rename to packages/material-ui-system/src/useThemeProps/getThemeProps.d.ts diff --git a/packages/material-ui/src/styles/getThemeProps.js b/packages/material-ui-system/src/useThemeProps/getThemeProps.js similarity index 100% rename from packages/material-ui/src/styles/getThemeProps.js rename to packages/material-ui-system/src/useThemeProps/getThemeProps.js diff --git a/packages/material-ui/src/styles/getThemeProps.test.js b/packages/material-ui-system/src/useThemeProps/getThemeProps.test.js similarity index 100% rename from packages/material-ui/src/styles/getThemeProps.test.js rename to packages/material-ui-system/src/useThemeProps/getThemeProps.test.js diff --git a/packages/material-ui-system/src/useThemeProps/index.d.ts b/packages/material-ui-system/src/useThemeProps/index.d.ts new file mode 100644 index 00000000000000..b8e70b1ea3d8af --- /dev/null +++ b/packages/material-ui-system/src/useThemeProps/index.d.ts @@ -0,0 +1,4 @@ +export { default } from './useThemeProps'; +export * from './useThemeProps'; + +export { default as getThemeProps } from './getThemeProps'; diff --git a/packages/material-ui-system/src/useThemeProps/index.js b/packages/material-ui-system/src/useThemeProps/index.js new file mode 100644 index 00000000000000..cac7b802d5d674 --- /dev/null +++ b/packages/material-ui-system/src/useThemeProps/index.js @@ -0,0 +1,2 @@ +export { default } from './useThemeProps'; +export { default as getThemeProps } from './getThemeProps'; diff --git a/packages/material-ui-system/src/useThemeProps/useThemeProps.d.ts b/packages/material-ui-system/src/useThemeProps/useThemeProps.d.ts new file mode 100644 index 00000000000000..db68dfaebaa29d --- /dev/null +++ b/packages/material-ui-system/src/useThemeProps/useThemeProps.d.ts @@ -0,0 +1,24 @@ +export interface ThemeWithProps { + components?: any; +} + +export type ThemedProps = Theme extends { + components: Record; +} + ? Props + : {}; + +export interface AdditionalThemeProps { + 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 & AdditionalThemeProps; diff --git a/packages/material-ui-system/src/useThemeProps/useThemeProps.js b/packages/material-ui-system/src/useThemeProps/useThemeProps.js new file mode 100644 index 00000000000000..4ae8eaeb5d7ac6 --- /dev/null +++ b/packages/material-ui-system/src/useThemeProps/useThemeProps.js @@ -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, + }; +} diff --git a/packages/material-ui-system/src/useThemeProps/useThemeProps.spec.ts b/packages/material-ui-system/src/useThemeProps/useThemeProps.spec.ts new file mode 100644 index 00000000000000..b4b3d0f9ea0bf9 --- /dev/null +++ b/packages/material-ui-system/src/useThemeProps/useThemeProps.spec.ts @@ -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({ + props: { color: 'primary' }, + name: 'MuiSlider', + }); + + // additional props are valid + expectType(props.isRtl); + expectType(props.theme); + + // component's props are valid + // Only existence of props is relevant here not type. + props.track; + props.valueLabelDisplay; +} diff --git a/packages/material-ui/src/SwipeableDrawer/SwipeableDrawer.js b/packages/material-ui/src/SwipeableDrawer/SwipeableDrawer.js index 0781e655cb6896..bd2931dc637403 100644 --- a/packages/material-ui/src/SwipeableDrawer/SwipeableDrawer.js +++ b/packages/material-ui/src/SwipeableDrawer/SwipeableDrawer.js @@ -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'; diff --git a/packages/material-ui/src/styles/useTheme.js b/packages/material-ui/src/styles/useTheme.js index 9c1e64147d12dc..5a7b3800d7fc8c 100644 --- a/packages/material-ui/src/styles/useTheme.js +++ b/packages/material-ui/src/styles/useTheme.js @@ -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 diff --git a/packages/material-ui/src/styles/useThemeProps.js b/packages/material-ui/src/styles/useThemeProps.js index 7b025fc8ece76a..7b8fd73d510d7a 100644 --- a/packages/material-ui/src/styles/useThemeProps.js +++ b/packages/material-ui/src/styles/useThemeProps.js @@ -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 }); } diff --git a/packages/material-ui/src/useMediaQuery/useMediaQuery.js b/packages/material-ui/src/useMediaQuery/useMediaQuery.js index d64f48cd8bcd55..83b580cc634930 100644 --- a/packages/material-ui/src/useMediaQuery/useMediaQuery.js +++ b/packages/material-ui/src/useMediaQuery/useMediaQuery.js @@ -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 = {}) {