Skip to content

Commit

Permalink
feat(framework): expose this.$vuetify (#13804)
Browse files Browse the repository at this point in the history
  • Loading branch information
KaelWD committed Jun 17, 2021
1 parent 232a5ff commit 76ad372
Show file tree
Hide file tree
Showing 12 changed files with 70 additions and 81 deletions.
16 changes: 8 additions & 8 deletions packages/vuetify/dev/Playground.template.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<template>
<div>
<!-- -->
</div>
<v-app>
<v-container>
<!-- -->
</v-container>
</v-app>
</template>

<script>
import { useVuetify } from 'vuetify'
export default {
name: 'Playground',
setup () {
const vuetify = useVuetify()
console.log(vuetify)
return {
//
}
},
}
</script>
10 changes: 0 additions & 10 deletions packages/vuetify/src/components/VGrid/__tests__/VCol.spec.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
import { mount } from '@vue/test-utils'

import VCol from '../VCol'
import * as framework from '@/framework'
import { createVuetify } from '@/framework'

describe('VCol', () => {
beforeEach(() => {
jest.spyOn(framework, 'useVuetify').mockReturnValue({
defaults: { global: {} },
})
})
afterEach(() => {
jest.spyOn(framework, 'useVuetify').mockRestore()
})

const vuetify = createVuetify()

function mountFunction (template: string) {
Expand Down
8 changes: 4 additions & 4 deletions packages/vuetify/src/components/VIcon/__tests__/VIcon.spec.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { VuetifyDefaultsSymbol } from '@/composables/defaults'
import { DefaultsSymbol } from '@/composables/defaults'
// Components
import { VIcon } from '..'

// Utilities
import { mount } from '@vue/test-utils'
import { defaultSets, VuetifyIconSymbol } from '@/composables/icons'
import { defaultSets, IconSymbol } from '@/composables/icons'
import { mdi } from '@/iconsets/mdi'
import { md } from '@/iconsets/md'
import { fa } from '@/iconsets/fa'
import { h, Text } from 'vue'

const globalOptions = {
provide: {
[VuetifyDefaultsSymbol as symbol]: {
[DefaultsSymbol as symbol]: {
value: { global: {} },
},
[VuetifyIconSymbol as symbol]: {
[IconSymbol as symbol]: {
defaultSet: 'mdi',
aliases: {
checkboxOn: 'mdi-check',
Expand Down
9 changes: 0 additions & 9 deletions packages/vuetify/src/components/VImg/__tests__/VImg.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,6 @@ describe('VImg', () => {
const LOAD_FAILURE_SRC = 'LOAD_FAILURE_SRC'
const LOAD_SUCCESS_SRC = 'LOAD_SUCCESS_SRC'

beforeEach(() => {
jest.spyOn(framework, 'useVuetify').mockReturnValue({
defaults: { global: {} },
})
})
afterEach(() => {
jest.spyOn(framework, 'useVuetify').mockRestore()
})

beforeAll(() => {
jest.useFakeTimers()
Object.defineProperty((global as any).Image.prototype, 'src', {
Expand Down
6 changes: 3 additions & 3 deletions packages/vuetify/src/composables/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ interface DefaultsInstance {

export type DefaultsOptions = Partial<DefaultsInstance>

export const VuetifyDefaultsSymbol: InjectionKey<Ref<DefaultsInstance>> = Symbol.for('vuetify:defaults')
export const DefaultsSymbol: InjectionKey<Ref<DefaultsInstance>> = Symbol.for('vuetify:defaults')

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

export function useDefaults () {
const defaults = inject(VuetifyDefaultsSymbol)
const defaults = inject(DefaultsSymbol)

if (!defaults) throw new Error('[Vuetify] Could not find defaults instance')

Expand All @@ -29,7 +29,7 @@ export function provideDefaults (props?: { defaults?: DefaultsInstance }) {

const newDefaults = computed(() => mergeDeep(defaults.value, props?.defaults) as any as DefaultsInstance)

provide(VuetifyDefaultsSymbol, newDefaults)
provide(DefaultsSymbol, newDefaults)

return newDefaults
}
4 changes: 2 additions & 2 deletions packages/vuetify/src/composables/display.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export interface DisplayInstance {
thresholds: DisplayThresholds
}

export const VuetifyDisplaySymbol: InjectionKey<ToRefs<DisplayInstance>> = Symbol.for('vuetify:display')
export const DisplaySymbol: InjectionKey<ToRefs<DisplayInstance>> = Symbol.for('vuetify:display')

const defaultDisplayOptions: DisplayOptions = {
mobileBreakpoint: 'lg',
Expand Down Expand Up @@ -204,7 +204,7 @@ export function createDisplay (options?: DisplayOptions): ToRefs<DisplayInstance
}

export function useDisplay () {
const display = inject(VuetifyDisplaySymbol)
const display = inject(DisplaySymbol)

if (!display) throw new Error('Could not find Vuetify display injection')

Expand Down
4 changes: 2 additions & 2 deletions packages/vuetify/src/composables/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ type IconInstance = {
icon: IconValue
}

export const VuetifyIconSymbol: InjectionKey<IconOptions> = Symbol.for('vuetify:icons')
export const IconSymbol: InjectionKey<IconOptions> = Symbol.for('vuetify:icons')

export const makeIconProps = propsFactory({
icon: {
Expand Down Expand Up @@ -159,7 +159,7 @@ export const defaultSets: Record<string, IconSet> = {

// Composables
export const useIcon = (props: Ref<string | undefined> | { icon?: IconValue }) => {
const icons = inject(VuetifyIconSymbol)
const icons = inject(IconSymbol)

if (!icons) throw new Error('Missing Vuetify Icons provide!')

Expand Down
6 changes: 3 additions & 3 deletions packages/vuetify/src/composables/locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,19 @@ export interface LocaleAdapter {
createScope: (options?: LocaleProps) => LocaleInstance
}

export const VuetifyLocaleAdapterSymbol: InjectionKey<LocaleAdapter> = Symbol.for('vuetify:locale-adapter')
export const LocaleAdapterSymbol: InjectionKey<LocaleAdapter> = Symbol.for('vuetify:locale-adapter')
export const VuetifyLocaleSymbol: InjectionKey<LocaleInstance> = Symbol.for('vuetify:locale')

export function provideLocale (props?: LocaleProps) {
const adapter = inject(VuetifyLocaleAdapterSymbol)
const adapter = inject(LocaleAdapterSymbol)

if (!adapter) throw new Error('[Vuetify] Could not find injected locale adapter')

return adapter.createScope(props)
}

export function useLocale () {
const adapter = inject(VuetifyLocaleAdapterSymbol)
const adapter = inject(LocaleAdapterSymbol)

if (!adapter) throw new Error('[Vuetify] Could not find injected locale adapter')

Expand Down
8 changes: 4 additions & 4 deletions packages/vuetify/src/composables/rtl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface RtlInstance {
rtlClasses: Ref<string>
}

export const VuetifyRtlSymbol: InjectionKey<RtlInstance> = Symbol.for('vuetify:rtl')
export const RtlSymbol: InjectionKey<RtlInstance> = Symbol.for('vuetify:rtl')

export function createRtl (localeScope: LocaleInstance, options?: RtlOptions) {
return createRtlScope({
Expand Down Expand Up @@ -51,19 +51,19 @@ export function createRtlScope (currentScope: RtlInstance, localeScope: LocaleIn
}

export function provideRtl (props: RtlProps, localeScope: LocaleInstance) {
const currentScope = inject(VuetifyRtlSymbol)
const currentScope = inject(RtlSymbol)

if (!currentScope) throw new Error('[Vuetify] Could not find injected rtl instance')

const newScope = createRtlScope(currentScope, localeScope, props)

provide(VuetifyRtlSymbol, newScope)
provide(RtlSymbol, newScope)

return newScope
}

export function useRtl () {
const currentScope = inject(VuetifyRtlSymbol)
const currentScope = inject(RtlSymbol)

if (!currentScope) throw new Error('[Vuetify] Could not find injected rtl instance')

Expand Down
6 changes: 3 additions & 3 deletions packages/vuetify/src/composables/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export interface ThemeInstance {
getTheme: (key: string) => InternalThemeDefinition
}

export const VuetifyThemeSymbol: InjectionKey<ThemeInstance> = Symbol.for('vuetify:theme')
export const ThemeSymbol: InjectionKey<ThemeInstance> = Symbol.for('vuetify:theme')

export const makeThemeProps = propsFactory({
theme: String,
Expand Down Expand Up @@ -295,7 +295,7 @@ export function createTheme (options?: ThemeOptions): ThemeInstance {
*/
export function useTheme (props: { theme?: string }) {
const vm = getCurrentInstance()
const theme = inject(VuetifyThemeSymbol, null)
const theme = inject(ThemeSymbol, null)

if (!vm) consoleError('provideTheme must be called from inside a setup function')
if (!theme) throw new Error('Could not find Vuetify theme injection')
Expand All @@ -312,7 +312,7 @@ export function useTheme (props: { theme?: string }) {
themeClasses,
}

provide(VuetifyThemeSymbol, newTheme)
provide(ThemeSymbol, newTheme)

return newTheme
}
73 changes: 40 additions & 33 deletions packages/vuetify/src/framework.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
// Composables
import { createDisplay, VuetifyDisplaySymbol } from '@/composables/display'
import { createTheme, VuetifyThemeSymbol } from '@/composables/theme'
import { defaultSets, VuetifyIconSymbol } from '@/composables/icons'
import { createDefaults, VuetifyDefaultsSymbol } from '@/composables/defaults'
import { createLocaleAdapter, VuetifyLocaleAdapterSymbol } from '@/composables/locale'
import { createRtl, VuetifyRtlSymbol } from '@/composables/rtl'
import { createDisplay, DisplaySymbol } from './composables/display'
import { createTheme, ThemeSymbol } from './composables/theme'
import { defaultSets, IconSymbol } from '@/composables/icons'
import { createDefaults, DefaultsSymbol } from '@/composables/defaults'
import { createLocaleAdapter, LocaleAdapterSymbol } from '@/composables/locale'
import { createRtl, RtlSymbol } from '@/composables/rtl'
import { aliases, mdi } from '@/iconsets/mdi'

// Utilities
import { inject } from 'vue'
import { reactive } from 'vue'
import { mergeDeep } from '@/util'

// Types
import type { App, InjectionKey } from 'vue'
import type { App, ComponentPublicInstance, InjectionKey } from 'vue'
import type { DisplayOptions } from '@/composables/display'
import type { ThemeOptions } from '@/composables/theme'
import type { IconOptions } from '@/composables/icons'
import type { LocaleAdapter, LocaleOptions } from '@/composables/locale'
import type { RtlOptions } from '@/composables/rtl'
import type { DefaultsOptions } from '@/composables/defaults'

export interface VuetifyInstance {}

export interface VuetifyOptions {
components?: Record<string, any>
directives?: Record<string, any>
Expand All @@ -32,18 +29,6 @@ export interface VuetifyOptions {
locale?: (LocaleOptions & RtlOptions) | (LocaleAdapter & RtlOptions)
}

export const VuetifySymbol: InjectionKey<VuetifyInstance> = Symbol.for('vuetify')

export const useVuetify = () => {
const vuetify = inject(VuetifySymbol)

if (!vuetify) {
throw new Error('Vuetify has not been installed on this app')
}

return vuetify
}

export const createVuetify = (options: VuetifyOptions = {}) => {
const install = (app: App) => {
const {
Expand All @@ -64,13 +49,10 @@ export const createVuetify = (options: VuetifyOptions = {}) => {
app.component(key, component)
}

const vuetify = {}

app.provide(VuetifySymbol, vuetify)
app.provide(VuetifyDefaultsSymbol, createDefaults(options.defaults))
app.provide(VuetifyDisplaySymbol, createDisplay(options.display))
app.provide(VuetifyThemeSymbol, createTheme(options.theme))
app.provide(VuetifyIconSymbol, mergeDeep({
app.provide(DefaultsSymbol, createDefaults(options.defaults))
app.provide(DisplaySymbol, createDisplay(options.display))
app.provide(ThemeSymbol, createTheme(options.theme))
app.provide(IconSymbol, mergeDeep({
defaultSet: 'mdi',
sets: {
...defaultSets,
Expand All @@ -79,9 +61,34 @@ export const createVuetify = (options: VuetifyOptions = {}) => {
aliases,
}, icons))
const { adapter, rootInstance } = createLocaleAdapter(app, options?.locale)
app.provide(VuetifyLocaleAdapterSymbol, adapter)
app.provide(VuetifyRtlSymbol, createRtl(rootInstance, options?.locale))
app.config.globalProperties.$vuetify = vuetify
app.provide(LocaleAdapterSymbol, adapter)
app.provide(RtlSymbol, createRtl(rootInstance, options?.locale))

// Vue's inject() can only be used in setup
function inject (this: ComponentPublicInstance, key: InjectionKey<any> | string) {
const vm = this.$

const provides = vm.parent?.provides ?? vm.vnode.appContext?.provides

if (provides && (key as any) in provides) {
return provides[(key as string)]
}
}

app.mixin({
computed: {
$vuetify () {
return reactive({
defaults: inject.call(this, DefaultsSymbol),
display: inject.call(this, DisplaySymbol),
theme: inject.call(this, ThemeSymbol),
icons: inject.call(this, IconSymbol),
locale: inject.call(this, LocaleAdapterSymbol),
rtl: inject.call(this, RtlSymbol),
})
},
},
})
}

return { install }
Expand Down
1 change: 1 addition & 0 deletions packages/vuetify/src/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ declare module 'vue' {
declare module '@vue/runtime-core' {
export interface ComponentInternalInstance {
ctx: Record<string, unknown>
provides: Record<string, unknown>
}
}

Expand Down

0 comments on commit 76ad372

Please sign in to comment.