element-plus/packages/hooks/use-css-var/index.ts
hangzou 65924dd40c
feat: new hook: useCssVar for inject custom css vars (#2547)
* feat: new hook: `usecssvars` for inject custom css vars

* perf: optimize usecssvar logic

* test: test css var
2021-07-20 15:26:17 +08:00

106 lines
2.1 KiB
TypeScript

import {
watch,
isRef,
onMounted,
computed,
unref,
inject,
onUnmounted,
provide,
ref,
} from 'vue'
import type { Ref, WatchStopHandle, InjectionKey } from 'vue'
type VarsType = Ref<Record<string, string>> | Record<string, string>
const VAR_PREFIX = '--el-'
const setVars = (
target: HTMLElement,
val: Record<string, string>,
) => {
Object.keys(val).forEach(key => {
if (key.startsWith(VAR_PREFIX)) {
target?.style.setProperty(key, val[key])
} else {
target?.style.setProperty(VAR_PREFIX + key, val[key])
}
})
}
export const themeVarsKey: InjectionKey<VarsType> = 'themeVars' as any
/**
* @param vars
* @param target
* @returns stopWatchHandler
* @example
*
* If you pass a Ref vars param, it will generate a watch handler.
*
* In main.ts:
*
* ```ts
* const themeVars = {
* '--el-color-primary': '#f44336',
* '--el-color-white': '#2196f3',
* }
* app.provide(themeVarsKey, themeVars)
* ```
* Usually you need to use this function in the root component.
* In components' steup:
*
* ```ts
* setup() {
* const themeVars = ref({
* '--el-button-default-background-color': '#f44336',
* '--el-button-default-font-color': '#2196f3',
* })
* useCssVar(themeVars)
* }
* ```
*/
export function useCssVar(
vars: VarsType,
target?: Ref<HTMLElement> | HTMLElement,
) {
let stopWatchCssVar: WatchStopHandle | null = null
const elRef = computed(
() => unref(target) || window?.document?.documentElement,
)
const themeVars = useThemeVars()
const customVars = { ...themeVars, ...unref(vars) }
provide(themeVarsKey, ref(customVars))
onMounted(() => {
isRef(vars)
? (stopWatchCssVar = watch(
vars,
val => {
setVars(elRef.value, {
...unref(themeVars),
...val,
})
},
{
immediate: true,
deep: true,
},
))
: setVars(elRef.value, {
...unref(themeVars),
...vars,
})
})
onUnmounted(() => stopWatchCssVar && stopWatchCssVar())
}
export const useThemeVars = () => {
const themeVars = inject(themeVarsKey, {})
return themeVars
}