From de559dd5285bcd7f2267631ba9990f5c70aed29b Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Wed, 26 Dec 2018 04:34:31 +0100 Subject: [PATCH] BREAKING: automatically determine partial theme type --- src/createThemeProvider.js | 14 +++++--------- src/createTheming.js | 10 +++++----- src/createWithTheme.js | 26 ++++++++++++++------------ typings/__tests__/index.test.tsx | 10 +++------- typings/index.d.ts | 26 +++++++++++--------------- 5 files changed, 38 insertions(+), 48 deletions(-) diff --git a/src/createThemeProvider.js b/src/createThemeProvider.js index fef4797..9ae1627 100644 --- a/src/createThemeProvider.js +++ b/src/createThemeProvider.js @@ -4,20 +4,16 @@ import * as React from 'react'; import type { Context } from 'create-react-context'; -type ThemeProviderProps = { - children?: any, - theme: T, -}; - -export type ThemeProviderType = React.ComponentType>; +export type ThemeProviderType = React.ComponentType<{ + children: React.Node, + theme?: T, +}>; function createThemeProvider( defaultTheme: T, ThemeContext: Context ): ThemeProviderType { - return class ThemeProvider extends React.PureComponent< - ThemeProviderProps - > { + return class ThemeProvider extends React.Component<*> { static defaultProps = { theme: defaultTheme, }; diff --git a/src/createTheming.js b/src/createTheming.js index 46e60f7..775728b 100644 --- a/src/createTheming.js +++ b/src/createTheming.js @@ -6,21 +6,21 @@ import createWithTheme from './createWithTheme'; import type { WithThemeType } from './createWithTheme'; import type { ThemeProviderType } from './createThemeProvider'; -export type ThemingType = { +export type ThemingType = { ThemeProvider: ThemeProviderType, - withTheme: WithThemeType, + withTheme: WithThemeType, }; -export default function createTheming( +export default function createTheming( defaultTheme: T -): ThemingType { +): ThemingType { const ThemeContext: Context = createReactContext(defaultTheme); const ThemeProvider: ThemeProviderType = createThemeProvider( defaultTheme, ThemeContext ); - const withTheme: WithThemeType = createWithTheme( + const withTheme: WithThemeType = createWithTheme( ThemeProvider, ThemeContext ); diff --git a/src/createWithTheme.js b/src/createWithTheme.js index 233f3a3..4de5fc8 100644 --- a/src/createWithTheme.js +++ b/src/createWithTheme.js @@ -10,17 +10,21 @@ import { copyRefs } from './utils'; import type { ThemeProviderType } from './createThemeProvider'; +type $DeepShape = $Shape< + $ObjMap(V) => $DeepShape) & ((V) => V)> +>; + const isClassComponent = (Component: any) => Boolean(Component.prototype && Component.prototype.isReactComponent); -export type WithThemeType = >( +export type WithThemeType = >( Comp: C ) => C & React.ComponentType< - $Diff, { theme: T }> & { theme?: S } + $Diff, { theme: T }> & { theme?: $DeepShape } >; -const createWithTheme = ( +const createWithTheme = >( ThemeProvider: ThemeProviderType, ThemeContext: Context ) => @@ -47,7 +51,6 @@ const createWithTheme = ( _root: any; render() { - const { forwardedRef, ...rest } = this.props; return ( {theme => { @@ -59,7 +62,7 @@ const createWithTheme = ( // It's needed to support use cases which need access to the underlying node element = ( { this._root = c; }} @@ -67,7 +70,7 @@ const createWithTheme = ( /> ); } else { - element = ; + element = ; } if (merged !== this.props.theme) { @@ -82,24 +85,23 @@ const createWithTheme = ( } } - let ComponentWithMethods = ThemedComponent; if (isClassComponent(Comp)) { // getWrappedInstance is exposed by some HOCs like react-redux's connect // Use it to get the ref to the underlying element // Also expose it to access the underlying element after wrapping // $FlowFixMe - ComponentWithMethods.prototype.getWrappedInstance = function getWrappedInstance() { - return this._root.getWrappedInstance + ThemedComponent.prototype.getWrappedInstance = function getWrappedInstance() { + return this._root && this._root.getWrappedInstance ? this._root.getWrappedInstance() : this._root; }; - ComponentWithMethods = copyRefs(ComponentWithMethods, Comp); + ThemedComponent = copyRefs(ThemedComponent, Comp); } - hoistNonReactStatics(ComponentWithMethods, Comp); + hoistNonReactStatics(ThemedComponent, Comp); - return (ComponentWithMethods: any); + return (ThemedComponent: any); }; export default createWithTheme; diff --git a/typings/__tests__/index.test.tsx b/typings/__tests__/index.test.tsx index 914f26d..bae6c44 100644 --- a/typings/__tests__/index.test.tsx +++ b/typings/__tests__/index.test.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import { createTheming } from "../.."; -export type Theme = { +type Theme = { primaryColor: string; accentColor: string; backgroundColor: string; @@ -9,11 +9,7 @@ export type Theme = { secondaryColor: string; }; -export type PartialTheme = { - primaryColor?: string; -}; - -export const themes: { [key: string]: Theme } = { +const themes: { [key: string]: Theme } = { default: { primaryColor: "#FFA72A", accentColor: "#458622", @@ -30,7 +26,7 @@ export const themes: { [key: string]: Theme } = { } }; -const { ThemeProvider, withTheme } = createTheming( +const { ThemeProvider, withTheme } = createTheming( themes.default ); diff --git a/typings/index.d.ts b/typings/index.d.ts index 2a6ed68..198d81b 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1,26 +1,22 @@ // Type definitions for @callstack/react-theme-provider 1.0.2 // TypeScript version 3.0.3 -import * as React from "react"; +import * as React from 'react'; -type Without = Pick>; +type $Without = Pick>; +type $DeepPartial = { [P in keyof T]?: $DeepPartial }; -export type ThemeProviderType = React.ComponentType<{ theme: Theme }>; - -export type ThemingType = { - ThemeProvider: ThemeProviderType; +export type ThemingType = { + ThemeProvider: React.ComponentType<{ theme?: Theme }>; withTheme: ( Comp: React.ComponentType - ) => React.ComponentType & { theme?: PartialTheme }>; + ) => React.ComponentType< + $Without & { theme?: $DeepPartial } + >; }; // Library exports -export const ThemeProvider: ThemeProviderType<{}>; - -export const withTheme: ( - Comp: React.ComponentType -) => React.ComponentType>; +export const ThemeProvider: ThemingType['ThemeProvider']; +export const withTheme: ThemingType['withTheme']; -export const createTheming: ( - defaultTheme: Theme -) => ThemingType; +export const createTheming: (defaultTheme: Theme) => ThemingType;