Skip to content

Commit

Permalink
fix(defaults): optimise defaults access
Browse files Browse the repository at this point in the history
see #16318
  • Loading branch information
KaelWD committed Jan 24, 2023
1 parent 1ed8295 commit a5539ba
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 23 deletions.
4 changes: 2 additions & 2 deletions packages/vuetify/src/composables/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, unknown>
global?: Record<string, unknown>
}
Expand All @@ -16,7 +16,7 @@ export type DefaultsOptions = Partial<DefaultsInstance>
export const DefaultsSymbol: InjectionKey<Ref<DefaultsInstance>> = Symbol.for('vuetify:defaults')

export function createDefaults (options?: DefaultsInstance): Ref<DefaultsInstance> {
return ref(options ?? {})
return ref(options)
}

export function useDefaults () {
Expand Down
44 changes: 24 additions & 20 deletions packages/vuetify/src/util/defineComponent.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -53,35 +52,40 @@ export const defineComponent = (function defineComponent (options: ComponentOpti

options.props._as = String
options.setup = function setup (props: Record<string, any>, 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
Expand Down
6 changes: 5 additions & 1 deletion packages/vuetify/src/util/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string>()

export type MaybeRef<T> = T | Ref<T>

Expand Down

0 comments on commit a5539ba

Please sign in to comment.