From 989c84ee711f77c032513406090123e1958c72f8 Mon Sep 17 00:00:00 2001 From: garronej Date: Mon, 23 Aug 2021 12:18:51 +0200 Subject: [PATCH] #16 withStyle implementation proposal --- .eslintrc.js | 2 ++ src/createMakeStyles.tsx | 8 ++--- src/index.ts | 8 ++++- src/tools/ReactComponent.ts | 5 ++++ src/withStyles.tsx | 60 +++++++++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 src/tools/ReactComponent.ts create mode 100644 src/withStyles.tsx diff --git a/.eslintrc.js b/.eslintrc.js index 42a33cc..5768fb6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -12,5 +12,7 @@ module.exports = { "rules": { "no-extra-boolean-cast": "off", "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/ban-types": "off" }, }; + diff --git a/src/createMakeStyles.tsx b/src/createMakeStyles.tsx index 8e7dd65..811efbc 100644 --- a/src/createMakeStyles.tsx +++ b/src/createMakeStyles.tsx @@ -15,7 +15,7 @@ export function createMakeStyles(params: { /** returns useStyle. */ function makeStyles() { return function ( - getCssObjectOrCssObject: + cssObjectOrGetCssObject: | (( theme: Theme, params: Params, @@ -24,9 +24,9 @@ export function createMakeStyles(params: { | Record, ) { const getCssObject = - typeof getCssObjectOrCssObject === "function" - ? getCssObjectOrCssObject - : () => getCssObjectOrCssObject; + typeof cssObjectOrGetCssObject === "function" + ? cssObjectOrGetCssObject + : () => cssObjectOrGetCssObject; function useStyles(params: Params) { const theme = useTheme(); diff --git a/src/index.ts b/src/index.ts index db32d28..6d9ad78 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,7 @@ import { insertStyles, getRegisteredStyles } from "@emotion/utils"; import type { EmotionCache } from "@emotion/cache"; import { useEmotionCache } from "./@emotion/react"; import { getCache } from "./cache"; +import { createWithStyles } from "./withStyles"; function createUseCssAndCx(params: { useEmotionCache(): EmotionCache }) { const { useEmotionCache } = params; @@ -37,13 +38,18 @@ export function createMakeStyles(params: { useCssAndCx, }); + const { withStyles } = createWithStyles({ + useTheme, + useCssAndCx, + }); + function useStyles() { const theme = useTheme(); const { css, cx } = useCssAndCx(); return { theme, css, cx }; } - return { makeStyles, useStyles }; + return { makeStyles, useStyles, withStyles }; } /** Reexport from @emotion/react */ diff --git a/src/tools/ReactComponent.ts b/src/tools/ReactComponent.ts new file mode 100644 index 0000000..b95338d --- /dev/null +++ b/src/tools/ReactComponent.ts @@ -0,0 +1,5 @@ +import type { FC, ComponentClass } from "react"; + +export type ReactComponent = {}> = + | ((props: Props) => ReturnType) + | ComponentClass; diff --git a/src/withStyles.tsx b/src/withStyles.tsx new file mode 100644 index 0000000..de34f41 --- /dev/null +++ b/src/withStyles.tsx @@ -0,0 +1,60 @@ +import type { ReactComponent } from "./tools/ReactComponent"; +import type { CSSObject, Css, Cx } from "./types"; +import { createMakeStyles } from "./createMakeStyles"; + +export function createWithStyles(params: { + useTheme(): Theme; + useCssAndCx(): { css: Css; cx: Cx }; +}) { + const { useTheme, useCssAndCx } = params; + + const { makeStyles } = createMakeStyles({ useTheme, useCssAndCx }); + + function withStyles< + Props extends Record, + C extends ReactComponent, + >( + Component: C, + cssObjectOrGetCssObject: + | CSSObject + | ((theme: Theme, props: Props, css: Css) => CSSObject), + ): C { + const useStyles = makeStyles()( + typeof cssObjectOrGetCssObject === "function" + ? (theme: Theme, props: Props, css: Css) => ({ + "root": cssObjectOrGetCssObject(theme, props, css), + }) + : { "root": cssObjectOrGetCssObject }, + ); + + const Out = function (props: Props) { + const { classes, cx } = useStyles(props); + + const { className, ...rest } = props; + + if (className !== undefined && typeof className !== "string") { + throw new Error(); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const Component_: ReactComponent = Component; + + return ( + + ); + }; + + const { name } = Component; + + if (typeof name === "string") { + Object.defineProperty(Out, "name", { + "value": `${name}WithStyles`, + }); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return Out as any; + } + + return { withStyles }; +}