forked from system-ui/theme-ui
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.ts
More file actions
120 lines (100 loc) · 3.17 KB
/
index.ts
File metadata and controls
120 lines (100 loc) · 3.17 KB
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import {
jsx as emotion,
ThemeContext as EmotionContext,
InterpolationWithTheme,
} from '@emotion/core'
import { css, Theme } from '@theme-ui/css'
import * as React from 'react'
import deepmerge from 'deepmerge'
import { version as __EMOTION_VERSION__ } from '@emotion/core/package.json'
import './react-jsx'
export * from './types'
const getCSS = (props) => {
if (!props.sx && !props.css) return undefined
return (theme) => {
const styles = css(props.sx)(theme)
const raw = typeof props.css === 'function' ? props.css(theme) : props.css
return [styles, raw]
}
}
const parseProps = (props) => {
if (!props) return null
const next: typeof props & { css?: InterpolationWithTheme<any> } = {}
for (let key in props) {
if (key === 'sx') continue
next[key] = props[key]
}
const css = getCSS(props)
if (css) next.css = css
return next
}
export const jsx: typeof React.createElement = (type, props, ...children) =>
emotion.apply(undefined, [type, parseProps(props), ...children])
export interface ContextValue {
__EMOTION_VERSION__: string
theme: Theme
colorMode?: string
setColorMode?: () => void
}
export const Context = React.createContext<ContextValue>({
__EMOTION_VERSION__,
theme: {},
})
export const useThemeUI = () => React.useContext(Context)
const canUseSymbol = typeof Symbol === 'function' && Symbol.for
const REACT_ELEMENT = canUseSymbol ? Symbol.for('react.element') : 0xeac7
const FORWARD_REF = canUseSymbol ? Symbol.for('react.forward_ref') : 0xeac7
const isMergeableObject = (n) => {
return (
!!n &&
typeof n === 'object' &&
n.$$typeof !== REACT_ELEMENT &&
n.$$typeof !== FORWARD_REF
)
}
const arrayMerge = (destinationArray, sourceArray, options) => sourceArray
/**
* Deeply merge themes
*/
export const merge = (a: Theme, b: Theme): Theme =>
deepmerge(a, b, { isMergeableObject, arrayMerge })
function mergeAll<A, B>(a: A, B: B): A & B
function mergeAll<A, B, C>(a: A, B: B, c: C): A & B & C
function mergeAll<A, B, C, D>(a: A, B: B, c: C, d: D): A & B & C & D
function mergeAll<T = Theme>(...args: Partial<T>[]) {
return deepmerge.all<T>(args, { isMergeableObject, arrayMerge })
}
merge.all = mergeAll
interface BaseProviderProps {
context: ContextValue
}
const BaseProvider: React.FC<BaseProviderProps> = ({ context, children }) =>
jsx(
EmotionContext.Provider,
{ value: context.theme },
jsx(Context.Provider, {
value: context,
children,
})
)
export interface ThemeProviderProps {
theme: Theme | ((outerTheme: Theme) => Theme)
children?: React.ReactNode
}
export function ThemeProvider({ theme, children }: ThemeProviderProps) {
const outer = useThemeUI()
if (process.env.NODE_ENV !== 'production') {
if (outer.__EMOTION_VERSION__ !== __EMOTION_VERSION__) {
console.warn(
'Multiple versions of Emotion detected,',
'and theming might not work as expected.',
'Please ensure there is only one copy of @emotion/core installed in your application.'
)
}
}
const context =
typeof theme === 'function'
? { ...outer, theme: theme(outer.theme) }
: merge.all({}, outer, { theme })
return jsx(BaseProvider, { context }, children)
}