From 0e82dacfd2434dcd05ca24c1cc9120f0e19171a4 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Thu, 11 Mar 2021 10:31:05 -0600 Subject: [PATCH] [CSS-in-JS] useEuiTheme & withEuiTheme refactor (#4594) * convert useEuiTheme to return object; refactor withEuiTheme types * readme update * update docs * Quick update to the docs Co-authored-by: cchaos --- src-docs/src/views/emotion/canopy.tsx | 38 ++++++++++------ src-docs/src/views/theme/computed.tsx | 10 ++-- src-docs/src/views/theme/consuming.tsx | 8 ++-- src-docs/src/views/theme/consuming_hoc.tsx | 10 ++-- src-docs/src/views/theme/create_computed.tsx | 24 +++++----- src-docs/src/views/theme/inverse.tsx | 8 ++-- src-docs/src/views/theme/override_simple.tsx | 6 +-- src-docs/src/views/theme/theme_example.js | 31 +++++++++++-- src/services/index.ts | 1 + src/services/theme/README.md | 4 +- src/services/theme/hooks.tsx | 48 ++++++++++---------- src/services/theme/index.ts | 2 +- 12 files changed, 113 insertions(+), 77 deletions(-) diff --git a/src-docs/src/views/emotion/canopy.tsx b/src-docs/src/views/emotion/canopy.tsx index abec3dcdc0c..efa9e84416b 100644 --- a/src-docs/src/views/emotion/canopy.tsx +++ b/src-docs/src/views/emotion/canopy.tsx @@ -26,6 +26,7 @@ import { mergeDeep, useEuiTheme, withEuiTheme, + WithEuiThemeProps, EuiThemeProvider, computed, euiThemeDefault, @@ -34,13 +35,13 @@ import { } from '../../../../src/services'; const View = () => { - const [theme, colorMode] = useEuiTheme(); + const { euiTheme, colorMode } = useEuiTheme(); return (
{colorMode}
-          {JSON.stringify(theme, null, 2)}
+          {JSON.stringify(euiTheme, null, 2)}
         
@@ -49,7 +50,7 @@ const View = () => { aria-hidden="true" type="stopFilled" size="xxl" - css={{ color: theme.colors.euiColorPrimary }} + css={{ color: euiTheme.colors.euiColorPrimary }} />

@@ -57,7 +58,7 @@ const View = () => { aria-hidden="true" type="stopFilled" size="xxl" - css={{ color: theme.colors.euiColorSecondary }} + css={{ color: euiTheme.colors.euiColorSecondary }} />

@@ -65,7 +66,7 @@ const View = () => { aria-hidden="true" type="stopFilled" size="xxl" - css={{ color: theme.colors.euiTextColor }} + css={{ color: euiTheme.colors.euiTextColor }} />

@@ -116,22 +117,28 @@ const View2 = () => { ); }; +interface BlockProps extends WithEuiThemeProps { + size?: 'xxl' | 'xl'; +} // eslint-disable-next-line react/prefer-stateless-function -class Block extends React.Component { +class Block extends React.Component { render() { - const { theme, ...props } = this.props; - // TODO: TS autocomplete not working + const { + theme: { euiTheme }, + size = 'xxl', + ...props + } = this.props; const blockStyle = css` - color: ${theme.theme.colors.euiColorPrimary}; - border-radius: ${theme.theme.borders.euiBorderRadiusSmall}; - border: ${theme.theme.borders.euiBorderEditable}; + color: ${euiTheme.colors.euiColorPrimary}; + border-radius: ${euiTheme.borders.euiBorderRadiusSmall}; + border: ${euiTheme.borders.euiBorderEditable}; `; return (
@@ -217,7 +224,10 @@ export default () => { const Extend = () => { // Generic type (ExtensionsComputed) necessary if accessing extensions/custom properties - const [{ colors, custom }, colorMode] = useEuiTheme(); + const { + euiTheme: { colors, custom }, + colorMode, + } = useEuiTheme(); return (
@@ -286,7 +296,7 @@ export default () => { Inverse colorMode withEuiTheme - + diff --git a/src-docs/src/views/theme/computed.tsx b/src-docs/src/views/theme/computed.tsx index 8932a5f1247..d2c404a0bc1 100644 --- a/src-docs/src/views/theme/computed.tsx +++ b/src-docs/src/views/theme/computed.tsx @@ -5,17 +5,17 @@ import { EuiText } from '../../../../src/components/text'; import { EuiThemeProvider, useEuiTheme } from '../../../../src/services'; const Box: FunctionComponent<{ children: ReactNode }> = ({ children }) => { - const [theme] = useEuiTheme(); + const { euiTheme } = useEuiTheme(); return (

- {' '} + {' '} {children}

diff --git a/src-docs/src/views/theme/consuming.tsx b/src-docs/src/views/theme/consuming.tsx index 9cdc7d2985f..202470ef893 100644 --- a/src-docs/src/views/theme/consuming.tsx +++ b/src-docs/src/views/theme/consuming.tsx @@ -4,22 +4,22 @@ import { EuiIcon } from '../../../../src/components/icon'; import { useEuiTheme } from '../../../../src/services'; export default () => { - const [theme] = useEuiTheme(); + const { euiTheme } = useEuiTheme(); return (

{' '} This primary color will adjust based on the light or dark theme value

The padding of this box is passed as a raw unit translated to pixels diff --git a/src-docs/src/views/theme/consuming_hoc.tsx b/src-docs/src/views/theme/consuming_hoc.tsx index 67d4b608988..8ef66de8bdd 100644 --- a/src-docs/src/views/theme/consuming_hoc.tsx +++ b/src-docs/src/views/theme/consuming_hoc.tsx @@ -1,18 +1,18 @@ import React from 'react'; import { css } from '@emotion/react'; -import { withEuiTheme } from '../../../../src/services'; +import { withEuiTheme, WithEuiThemeProps } from '../../../../src/services'; import { EuiIcon } from '../../../../src/components/icon'; // eslint-disable-next-line react/prefer-stateless-function -class Block extends React.Component { +class Block extends React.Component { render() { const { theme } = this.props; const divStyle = css` - background: ${theme.theme.colors.euiColorLightShade}; + background: ${theme.euiTheme.colors.euiColorLightShade}; // This way of providing sizing values doesn't output correctly - padding: ${theme.theme.sizes.euiSizeXL}; - border-radius: ${theme.theme.borders.euiBorderRadius}; + padding: ${theme.euiTheme.sizes.euiSizeXL}; + border-radius: ${theme.euiTheme.borders.euiBorderRadius}; `; return ( diff --git a/src-docs/src/views/theme/create_computed.tsx b/src-docs/src/views/theme/create_computed.tsx index 32497587d5d..9bc013ffaab 100644 --- a/src-docs/src/views/theme/create_computed.tsx +++ b/src-docs/src/views/theme/create_computed.tsx @@ -9,24 +9,26 @@ import { useEuiTheme, } from '../../../../src/services'; +interface ThemeExtensions { + colors: { + customColorPrimary: string; + customColorPrimaryHighlight: string; + customColorPrimaryText: string; + }; +} + const Box: FunctionComponent<{ children: ReactNode }> = ({ children }) => { - const [theme] = useEuiTheme(); + const { euiTheme } = useEuiTheme(); return (

- {' '} + {' '} {children}

diff --git a/src-docs/src/views/theme/inverse.tsx b/src-docs/src/views/theme/inverse.tsx index cbdf8ceac79..3eec2b1b138 100644 --- a/src-docs/src/views/theme/inverse.tsx +++ b/src-docs/src/views/theme/inverse.tsx @@ -4,14 +4,14 @@ import { EuiSpacer } from '../../../../src/components/spacer'; import { EuiThemeProvider, useEuiTheme } from '../../../../src/services'; const Box: FunctionComponent<{ children: ReactNode }> = ({ children }) => { - const [theme] = useEuiTheme(); + const { euiTheme } = useEuiTheme(); return (

{children}

diff --git a/src-docs/src/views/theme/override_simple.tsx b/src-docs/src/views/theme/override_simple.tsx index 2b8e394cac9..23b7b103118 100644 --- a/src-docs/src/views/theme/override_simple.tsx +++ b/src-docs/src/views/theme/override_simple.tsx @@ -3,13 +3,13 @@ import { EuiCode } from '../../../../src/components/code'; import { EuiThemeProvider, useEuiTheme } from '../../../../src/services'; const Box: FunctionComponent<{ children: ReactNode }> = ({ children }) => { - const [theme] = useEuiTheme(); + const { euiTheme } = useEuiTheme(); return (

{children}

diff --git a/src-docs/src/views/theme/theme_example.js b/src-docs/src/views/theme/theme_example.js index dd76e441eb8..00adf63bca5 100644 --- a/src-docs/src/views/theme/theme_example.js +++ b/src-docs/src/views/theme/theme_example.js @@ -77,13 +77,31 @@ export const ThemeExample = { <>

Using the react hook useEuiTheme() makes it very - easy to consume the EUI static variables like colors and sizing. It - will also automatically update based on the currently used theme. + easy to consume the EUI static and computed variables like colors + and sizing. It simply passes back an object of the current theme + which includes

+
    +
  • + euiTheme: EuiThemeComputed All + the calculated keys including any modifications +
  • +
  • + colorMode: EuiThemeColorMode{' '} + Simply {"'light'"} or {"'dark'"} +
  • +
  • + + modifications: EuiThemeModifications + {' '} + Only the modification keys +
  • +

- You'll want to pass these theme variables via the{' '} - css property to take advantage of Emotion's - compilation. + When consuming the theme's keys like{' '} + euiTheme.colors.primary, you'll want to pass + them via the css property to take advantage of + Emotion's compilation.

), @@ -217,6 +235,9 @@ export const ThemeExample = { specific theme variables. Instead, you should append custom keys to the theme.

+

+ TODO: Indicate type support for custom keys. +

), demo: , diff --git a/src/services/index.ts b/src/services/index.ts index 2c3cb251a66..bc5538365f9 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -129,6 +129,7 @@ export { EuiColorModeContext, useEuiTheme, withEuiTheme, + WithEuiThemeProps, EuiThemeProvider, buildTheme, computed, diff --git a/src/services/theme/README.md b/src/services/theme/README.md index 48e65de41f3..59aea98c0d0 100644 --- a/src/services/theme/README.md +++ b/src/services/theme/README.md @@ -93,10 +93,10 @@ All three props are optional. The default values for EUI will be used in the eve A custom React hook that returns the computed theme. This hook is little more than a wrapper around the `useContext` hook, accessing three of the top-level providers: computed theme, color mode, and modifications. ```js -const [theme, colorMode, modifications] = useEuiTheme(); +const {euiTheme, colorMode, modifications} = useEuiTheme(); ``` -The `theme` variable has TypeScript support, which will result in IDE autocomplete availability. +The `euiTheme` variable has TypeScript support, which will result in IDE autocomplete availability. ### WithEuiTheme A higher-order-component that wraps `useEuiTheme` for React class components. diff --git a/src/services/theme/hooks.tsx b/src/services/theme/hooks.tsx index ee7e8065349..7a56137a6ab 100644 --- a/src/services/theme/hooks.tsx +++ b/src/services/theme/hooks.tsx @@ -30,43 +30,45 @@ import { EuiThemeComputed, } from './types'; -export const useEuiTheme = (): [ - EuiThemeComputed, - EuiThemeColorMode, - EuiThemeModifications -] => { +export const useEuiTheme = (): { + euiTheme: EuiThemeComputed; + colorMode: EuiThemeColorMode; + modifications: EuiThemeModifications; +} => { const theme = useContext(EuiThemeContext); - const modifications = useContext(EuiModificationsContext); const colorMode = useContext(EuiColorModeContext); + const modifications = useContext(EuiModificationsContext); - return [ - theme as EuiThemeComputed, + return { + euiTheme: theme as EuiThemeComputed, colorMode, - modifications as EuiThemeModifications, - ]; + modifications: modifications as EuiThemeModifications, + }; }; -export const withEuiTheme = ( - Component: React.ComponentType< - T & { - theme: { - theme: EuiThemeComputed; - colorMode: EuiThemeColorMode; - }; - } - > +export interface WithEuiThemeProps

{ + theme: { + euiTheme: EuiThemeComputed

; + colorMode: EuiThemeColorMode; + }; +} +export const withEuiTheme = ( + Component: React.ComponentType> ) => { const componentName = Component.displayName || Component.name || 'Component'; - const Render = (props: T, ref: React.Ref) => { - const [theme, colorMode] = useEuiTheme(); + const Render = ( + props: Omit>, + ref: React.Ref>> + ) => { + const { euiTheme, colorMode } = useEuiTheme(); return ( ); }; diff --git a/src/services/theme/index.ts b/src/services/theme/index.ts index 58ada6c9dc6..d7e299b0a43 100644 --- a/src/services/theme/index.ts +++ b/src/services/theme/index.ts @@ -23,7 +23,7 @@ export { EuiModificationsContext, EuiColorModeContext, } from './context'; -export { useEuiTheme, withEuiTheme } from './hooks'; +export { useEuiTheme, withEuiTheme, WithEuiThemeProps } from './hooks'; export { EuiThemeProvider } from './provider'; export { buildTheme,