From a5539ba721a29e42c4e51f764d9944a6f51c2e28 Mon Sep 17 00:00:00 2001 From: Kael Date: Tue, 24 Jan 2023 18:04:54 +1100 Subject: [PATCH] fix(defaults): optimise defaults access see #16318 --- packages/vuetify/src/composables/defaults.ts | 4 +- packages/vuetify/src/util/defineComponent.tsx | 44 ++++++++++--------- packages/vuetify/src/util/helpers.ts | 6 ++- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/packages/vuetify/src/composables/defaults.ts b/packages/vuetify/src/composables/defaults.ts index aeaa04e3ad1..58cb8fc5fe0 100644 --- a/packages/vuetify/src/composables/defaults.ts +++ b/packages/vuetify/src/composables/defaults.ts @@ -6,7 +6,7 @@ import { mergeDeep } from '@/util' import type { ComputedRef, InjectionKey, Ref } from 'vue' import type { MaybeRef } from '@/util' -export interface DefaultsInstance { +export type DefaultsInstance = undefined | { [key: string]: undefined | Record global?: Record } @@ -16,7 +16,7 @@ export type DefaultsOptions = Partial export const DefaultsSymbol: InjectionKey> = Symbol.for('vuetify:defaults') export function createDefaults (options?: DefaultsInstance): Ref { - return ref(options ?? {}) + return ref(options) } export function useDefaults () { diff --git a/packages/vuetify/src/util/defineComponent.tsx b/packages/vuetify/src/util/defineComponent.tsx index 41437857998..41b2d6a4b83 100644 --- a/packages/vuetify/src/util/defineComponent.tsx +++ b/packages/vuetify/src/util/defineComponent.tsx @@ -1,10 +1,9 @@ // Utils import { defineComponent as _defineComponent, // eslint-disable-line no-restricted-imports + computed, getCurrentInstance, - shallowReactive, shallowRef, - toRaw, watchEffect, } from 'vue' import { consoleWarn } from '@/util/console' @@ -53,35 +52,40 @@ export const defineComponent = (function defineComponent (options: ComponentOpti options.props._as = String options.setup = function setup (props: Record, ctx) { - const vm = getCurrentInstance()! const defaults = useDefaults() - const _subcomponentDefaults = shallowRef() - const _props = shallowReactive({ ...toRaw(props) }) - watchEffect(() => { - const globalDefaults = defaults.value.global - const componentDefaults = defaults.value[props._as ?? options.name!] + // Skip props proxy if defaults are not provided + if (!defaults.value) return options._setup(props, ctx) - if (componentDefaults) { - const subComponents = Object.entries(componentDefaults).filter(([key]) => key.startsWith(key[0].toUpperCase())) - if (subComponents.length) _subcomponentDefaults.value = Object.fromEntries(subComponents) - } - - for (const prop of Object.keys(props)) { - let newVal = props[prop] + const vm = getCurrentInstance()! + const componentDefaults = computed(() => defaults.value![props._as ?? options.name!]) + const _props = new Proxy(props, { + get (target, prop: string) { if (!propIsDefined(vm.vnode, prop)) { - newVal = componentDefaults?.[prop] ?? globalDefaults?.[prop] ?? props[prop] - } - if (_props[prop] !== newVal) { - _props[prop] = newVal + return componentDefaults.value?.[prop] ?? defaults.value!.global?.[prop] ?? target[prop] } + return Reflect.get(target, prop) + }, + }) + + const _subcomponentDefaults = shallowRef() + watchEffect(() => { + if (componentDefaults.value) { + const subComponents = Object.entries(componentDefaults.value).filter(([key]) => key.startsWith(key[0].toUpperCase())) + if (subComponents.length) _subcomponentDefaults.value = Object.fromEntries(subComponents) } }) const setupBindings = options._setup(_props, ctx) + // If subcomponent defaults are provided, override any + // subcomponents provided by the component's setup function. + // This uses injectSelf so must be done after the original setup to work. useToggleScope(_subcomponentDefaults, () => { - provideDefaults(mergeDeep(injectSelf(DefaultsSymbol)?.value ?? {}, _subcomponentDefaults.value)) + provideDefaults(mergeDeep( + injectSelf(DefaultsSymbol)?.value ?? {}, + _subcomponentDefaults.value + )) }) return setupBindings diff --git a/packages/vuetify/src/util/helpers.ts b/packages/vuetify/src/util/helpers.ts index 4a1fb9872ec..4b10183bc49 100644 --- a/packages/vuetify/src/util/helpers.ts +++ b/packages/vuetify/src/util/helpers.ts @@ -454,11 +454,15 @@ export const randomHexColor = () => { } export function toKebabCase (str = '') { - return str + if (toKebabCase.cache.has(str)) return toKebabCase.cache.get(str)! + const kebab = str .replace(/[^a-z]/gi, '-') .replace(/\B([A-Z])/g, '-$1') .toLowerCase() + toKebabCase.cache.set(str, kebab) + return kebab } +toKebabCase.cache = new Map() export type MaybeRef = T | Ref