From bd0a63406939af0dfef519ae28a42de6e9393edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90?= Date: Sat, 1 Jan 2022 13:43:08 +0800 Subject: [PATCH] refactor(utils)!: remove global config (#5093) --- .../config-provider/src/config-provider.ts | 25 ++++------- packages/element-plus/make-installer.ts | 17 +++++++- packages/hooks/use-global-config/index.ts | 43 ++++++++++++++++--- packages/tokens/config-provider.ts | 7 +-- packages/utils/util.ts | 11 +++++ 5 files changed, 75 insertions(+), 28 deletions(-) diff --git a/packages/components/config-provider/src/config-provider.ts b/packages/components/config-provider/src/config-provider.ts index 1c9f4ab25b..47218e576b 100644 --- a/packages/components/config-provider/src/config-provider.ts +++ b/packages/components/config-provider/src/config-provider.ts @@ -1,9 +1,10 @@ -import { provide, defineComponent, watch } from 'vue' +import { defineComponent, renderSlot } from 'vue' import { buildProps, definePropType } from '@element-plus/utils/props' -import { useLocaleProps, provideLocale } from '@element-plus/hooks' -import { configProviderContextKey } from '@element-plus/tokens' -import { PopupManager } from '@element-plus/utils/popup-manager' -import { isNumber } from '@element-plus/utils/util' +import { + useLocaleProps, + provideLocale, + provideGlobalConfig, +} from '@element-plus/hooks' import type { ButtonConfigContext } from '@element-plus/components/button' export const configProviderProps = buildProps({ @@ -29,17 +30,7 @@ export default defineComponent({ setup(props, { slots }) { provideLocale() - provide(configProviderContextKey, props) - - watch( - () => props.zIndex, - () => { - if (isNumber(props.zIndex)) - PopupManager.globalInitialZIndex = props.zIndex - }, - { immediate: true } - ) - - return () => slots.default?.() + const config = provideGlobalConfig(props) + return () => renderSlot(slots, 'default', { config: config?.value }) }, }) diff --git a/packages/element-plus/make-installer.ts b/packages/element-plus/make-installer.ts index 47e7ac2210..28be568fd2 100644 --- a/packages/element-plus/make-installer.ts +++ b/packages/element-plus/make-installer.ts @@ -1,14 +1,29 @@ +import { watch, unref } from 'vue' +import { provideGlobalConfig } from '@element-plus/hooks' +import { isNumber } from '@element-plus/utils/util' +import { PopupManager } from '@element-plus/utils/popup-manager' import { version } from './version' import type { App, Plugin } from 'vue' +import type { ConfigProviderContext } from '@element-plus/tokens' const INSTALLED_KEY = Symbol('INSTALLED_KEY') export const makeInstaller = (components: Plugin[] = []) => { - const install = (app: App) => { + const install = (app: App, options: ConfigProviderContext = {}) => { if (app[INSTALLED_KEY]) return app[INSTALLED_KEY] = true components.forEach((c) => app.use(c)) + provideGlobalConfig(options, app) + + watch( + () => unref(options).zIndex, + () => { + const zIndex = unref(options).zIndex + if (isNumber(zIndex)) PopupManager.globalInitialZIndex = zIndex + }, + { immediate: true } + ) } return { diff --git a/packages/hooks/use-global-config/index.ts b/packages/hooks/use-global-config/index.ts index f7302397f7..4228bd054b 100644 --- a/packages/hooks/use-global-config/index.ts +++ b/packages/hooks/use-global-config/index.ts @@ -1,20 +1,49 @@ -import { inject, ref, toRef } from 'vue' +import { inject, ref, computed, unref, provide, getCurrentInstance } from 'vue' import { configProviderContextKey } from '@element-plus/tokens' -import { hasOwn, isObject } from '@element-plus/utils/util' -import type { Ref } from 'vue' +import { hasOwn, isObject, merge } from '@element-plus/utils/util' +import { debugWarn } from '@element-plus/utils/error' +import type { MaybeRef } from '@vueuse/core' +import type { Ref, App } from 'vue' import type { ConfigProviderContext } from '@element-plus/tokens' +const fallback = ref({}) + export function useGlobalConfig( key: K ): Ref -export function useGlobalConfig(): ConfigProviderContext +export function useGlobalConfig(): Ref export function useGlobalConfig(key?: keyof ConfigProviderContext) { - const config = inject(configProviderContextKey, {}) + const config = inject(configProviderContextKey, fallback) if (key) { - return isObject(config) && hasOwn(config, key) - ? toRef(config, key) + return isObject(config.value) && hasOwn(config.value, key) + ? computed(() => config.value[key]) : ref(undefined) } else { return config } } + +export const provideGlobalConfig = ( + config: MaybeRef, + app?: App +) => { + const inSetup = !!getCurrentInstance() + const oldConfig = inSetup ? useGlobalConfig() : undefined + + const provideFn = app?.provide ?? (inSetup ? provide : undefined) + if (!provideFn) { + debugWarn( + 'provideGlobalConfig', + 'provideGlobalConfig() can only be used inside setup().' + ) + return + } + + const context = computed(() => { + const cfg = unref(config) + if (!oldConfig) return cfg + return merge(oldConfig.value, cfg) + }) + provideFn(configProviderContextKey, context) + return context +} diff --git a/packages/tokens/config-provider.ts b/packages/tokens/config-provider.ts index 429b4ddb3d..ce6d9dd9e0 100644 --- a/packages/tokens/config-provider.ts +++ b/packages/tokens/config-provider.ts @@ -1,7 +1,8 @@ import type { configProviderProps } from '@element-plus/components/config-provider' -import type { InjectionKey, ExtractPropTypes } from 'vue' +import type { InjectionKey, ExtractPropTypes, Ref } from 'vue' export type ConfigProviderContext = ExtractPropTypes -export const configProviderContextKey: InjectionKey = - Symbol() +export const configProviderContextKey: InjectionKey< + Ref +> = Symbol() diff --git a/packages/utils/util.ts b/packages/utils/util.ts index 291db9f994..70975cb532 100644 --- a/packages/utils/util.ts +++ b/packages/utils/util.ts @@ -239,3 +239,14 @@ export const refAttacher = ( ref.value = val } } + +export const merge = >(a: T, b: T) => { + const keys = [ + ...new Set([...Object.keys(a), ...Object.keys(b)]), + ] as (keyof T)[] + const obj = {} as T + for (const key of keys) { + obj[key] = b[key] ?? a[key] + } + return obj +}