mirror of
https://github.com/zhigang1992/react.git
synced 2026-04-28 20:25:29 +08:00
77 lines
2.4 KiB
TypeScript
77 lines
2.4 KiB
TypeScript
import React, { PropsWithChildren } from 'react'
|
|
import useTheme from '../use-theme'
|
|
import darkTheme from '../themes/dark'
|
|
import lightTheme from '../themes/default'
|
|
import { ZeitUIThemes } from '../themes/index'
|
|
import ThemeContext from '../use-theme/theme-context'
|
|
import useWarning from '../../utils/use-warning'
|
|
import { DeepPartial } from '../../utils/types'
|
|
|
|
type PartialTheme = DeepPartial<ZeitUIThemes>
|
|
export type ThemeParam = PartialTheme | ((theme: PartialTheme) => PartialTheme) | undefined
|
|
|
|
export interface Props {
|
|
theme?: ThemeParam
|
|
}
|
|
|
|
export interface MergeObject {
|
|
[key: string]: any
|
|
}
|
|
|
|
export const isObject = (target: any) => target && typeof target === 'object'
|
|
|
|
export const deepMergeObject = <T extends MergeObject,>(source: T, target: T): T => {
|
|
if (!isObject(target) || !isObject(source)) return source
|
|
|
|
const sourceKeys = Object.keys(source) as Array<keyof T>
|
|
let result = {} as T
|
|
for (const key of sourceKeys) {
|
|
const sourceValue = source[key]
|
|
const targetValue = target[key]
|
|
|
|
if (Array.isArray(sourceValue) && Array.isArray(targetValue)) {
|
|
result[key] = targetValue.concat(sourceValue)
|
|
} else if (isObject(sourceValue) && isObject(targetValue)) {
|
|
result[key] = deepMergeObject(sourceValue, { ...targetValue })
|
|
} else if (targetValue) {
|
|
result[key] = targetValue
|
|
} else {
|
|
result[key] = sourceValue
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
const mergeTheme = (current: ZeitUIThemes, custom: ThemeParam): ZeitUIThemes => {
|
|
if (!custom) return current
|
|
if (typeof custom === 'function') {
|
|
const merged = custom(current)
|
|
if (!merged || typeof merged !== 'object') {
|
|
useWarning('The theme function must return object value.')
|
|
}
|
|
return merged as ZeitUIThemes
|
|
}
|
|
return deepMergeObject<ZeitUIThemes>(current, custom as ZeitUIThemes)
|
|
}
|
|
|
|
const switchTheme = (mergedTheme: ZeitUIThemes): ZeitUIThemes => {
|
|
const themes: { [key in ZeitUIThemes['type']]: ZeitUIThemes } = {
|
|
light: lightTheme,
|
|
dark: darkTheme,
|
|
}
|
|
return {...mergedTheme, ...themes[mergedTheme.type]}
|
|
}
|
|
|
|
const ThemeProvider: React.FC<PropsWithChildren<Props>> = ({ children, theme }) => {
|
|
const customTheme = theme
|
|
const currentTheme = useTheme()
|
|
const merged = mergeTheme(currentTheme, customTheme)
|
|
const userTheme = currentTheme.type !== merged.type ? switchTheme(merged) : merged
|
|
|
|
return (
|
|
<ThemeContext.Provider value={userTheme}>{children}</ThemeContext.Provider>
|
|
)
|
|
}
|
|
|
|
export default ThemeProvider
|