Spaces:
Sleeping
Sleeping
File size: 2,921 Bytes
56fda74 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
import * as React from 'react'
import weakMemoize from '@emotion/weak-memoize'
import isDevelopment from '#is-development'
import hoistNonReactStatics from './_isolated-hnrs'
import { DistributiveOmit, PropsOf } from './types'
// tslint:disable-next-line: no-empty-interface
export interface Theme {}
export interface ThemeProviderProps {
theme: Partial<Theme> | ((outerTheme: Theme) => Theme)
children: React.ReactNode
}
export interface ThemeProvider {
(props: ThemeProviderProps): React.ReactElement
}
export type WithTheme<P, T> = P extends { theme: infer Theme }
? P & { theme: Exclude<Theme, undefined> }
: P & { theme: T }
export const ThemeContext = /* #__PURE__ */ React.createContext({} as Theme)
if (isDevelopment) {
ThemeContext.displayName = 'EmotionThemeContext'
}
export const useTheme = () => React.useContext(ThemeContext)
const getTheme = (
outerTheme: Theme,
theme: Partial<Theme> | ((theme: Theme) => Theme)
): Theme => {
if (typeof theme === 'function') {
const mergedTheme = theme(outerTheme)
if (
isDevelopment &&
(mergedTheme == null ||
typeof mergedTheme !== 'object' ||
Array.isArray(mergedTheme))
) {
throw new Error(
'[ThemeProvider] Please return an object from your theme function, i.e. theme={() => ({})}!'
)
}
return mergedTheme
}
if (
isDevelopment &&
(theme == null || typeof theme !== 'object' || Array.isArray(theme))
) {
throw new Error(
'[ThemeProvider] Please make your theme prop a plain object'
)
}
return { ...outerTheme, ...theme }
}
let createCacheWithTheme = /* #__PURE__ */ weakMemoize((outerTheme: Theme) => {
return weakMemoize((theme: Partial<Theme> | ((theme: Theme) => Theme)) => {
return getTheme(outerTheme, theme)
})
})
export interface ThemeProviderProps {
theme: Partial<Theme> | ((outerTheme: Theme) => Theme)
children: React.ReactNode
}
export const ThemeProvider = (props: ThemeProviderProps) => {
let theme = React.useContext(ThemeContext)
if (props.theme !== theme) {
theme = createCacheWithTheme(theme)(props.theme)
}
return (
<ThemeContext.Provider value={theme}>
{props.children}
</ThemeContext.Provider>
)
}
export function withTheme<
C extends React.ComponentType<React.ComponentProps<C>>
>(
Component: C
): React.ForwardRefExoticComponent<
DistributiveOmit<PropsOf<C>, 'theme'> & { theme?: Theme }
>
export function withTheme(
Component: React.ComponentType<any>
): React.ForwardRefExoticComponent<any> {
const componentName = Component.displayName || Component.name || 'Component'
let WithTheme = React.forwardRef(function render(props, ref) {
let theme = React.useContext(ThemeContext)
return <Component theme={theme} ref={ref} {...props} />
})
WithTheme.displayName = `WithTheme(${componentName})`
return hoistNonReactStatics(WithTheme, Component)
}
|