diff --git a/packages/ui/src/components/va-modal/hooks/useModal.ts b/packages/ui/src/components/va-modal/hooks/useModal.ts index 8545562ef7..d61a3f0700 100644 --- a/packages/ui/src/components/va-modal/hooks/useModal.ts +++ b/packages/ui/src/components/va-modal/hooks/useModal.ts @@ -1,10 +1,14 @@ +import { getCurrentInstance } from 'vue' import { createModalInstance } from '../modal' import { ModalOptions } from '../types' -import { getCurrentApp } from '../../../services/current-app' /** This hook can be used without plugin used */ export const useModal = () => { - const appContext = getCurrentApp()._context + const appContext = getCurrentInstance()?.appContext + + if (!appContext) { + throw new Error('useModal can be used only in setup function. You can use app.config.globalProperties.$vaModal outside setup function') + } /** * @param options can be message string or options object diff --git a/packages/ui/src/components/va-modal/types.ts b/packages/ui/src/components/va-modal/types.ts index 96461dc044..87b51ecd95 100644 --- a/packages/ui/src/components/va-modal/types.ts +++ b/packages/ui/src/components/va-modal/types.ts @@ -1,5 +1,6 @@ import { ExtractComponentPropTypes } from '../../utils/component-options' import VaModal from './VaModal.vue' +import { ExtractPropTypes } from 'vue' export type ModalSize = 'small' | 'medium' | 'large' @@ -14,4 +15,4 @@ export type ModalEmits = { 'onUpdate:modelValue'?: (value: boolean) => void; } -export type ModalOptions = Partial, 'anchorClass'>> & ModalEmits +export type ModalOptions = Partial & ModalEmits, 'anchorClass'>> diff --git a/packages/ui/src/components/va-toast/hooks/useToast.ts b/packages/ui/src/components/va-toast/hooks/useToast.ts index 2be50a910b..e93eda7ea2 100644 --- a/packages/ui/src/components/va-toast/hooks/useToast.ts +++ b/packages/ui/src/components/va-toast/hooks/useToast.ts @@ -1,9 +1,10 @@ +import { getCurrentInstance } from 'vue' + import { createToastInstance, closeById, closeAllNotifications, NotificationOptions } from '../toast' -import { getCurrentApp } from '../../../services/current-app' /** This hook can be used without plugin used */ export const useToast = () => { - const appContext = getCurrentApp()._context + const appContext = getCurrentInstance()?.appContext const createdInThisSetupContext: string[] = [] diff --git a/packages/ui/src/services/current-app.ts b/packages/ui/src/services/current-app.ts index 089d20161e..1b6675ef28 100644 --- a/packages/ui/src/services/current-app.ts +++ b/packages/ui/src/services/current-app.ts @@ -1,52 +1,17 @@ -import type { App, provide as vueProvide } from 'vue' -import { inject as vueInject, getCurrentInstance } from 'vue' +import type { App } from 'vue' +import { inject as vueInject } from 'vue' /** * Similar to `getCurrentInstance` but for plugins, so we can use inject in plugins. */ let app: App | null -let singleApp: App | null | undefined -export const setCurrentApp = (instance: App | null) => { - app = instance +export const setCurrentApp = (instance: App | null) => { app = instance } +export const getCurrentApp = () => app - if (singleApp && instance !== singleApp) { - // This means that user has multiple apps on page. - singleApp = null - } else { - singleApp = instance - } -} - -/** - * Returns current app if Vuestic UI is used in single app mode. - * - * @throws Error if Vuestic UI is used in multiple apps. - * @throws Error if Vuestic UI plugin is not installed. - */ -export const getCurrentApp = () => { - const app = getCurrentInstance()?.appContext.app - if (app) { return app } - - if (singleApp === undefined) { - throw new Error('Vuestic UI plugin is not installed.') - } - if (singleApp === null) { - throw new Error('Vuestic UI is used in multiple apps. You`re not allowed to use composable outside of setup function context.') - } - return singleApp -} - -/** Wrapper around vue inject, so we can use it in plugins and outside of setup context if only one app is used */ +/** Wrapper around vue inject, so it can be used in plugins */ export const inject = ((key: string, value?: any) => { const app = getCurrentApp()?._context.provides[key] return app || vueInject(key, value) -}) as typeof vueInject - -/** Wrapper around vue provide, so we can use it in plugins and outside of setup context if only one app is used */ -export const provide = ((key: string, value: any) => { - const provides = getCurrentInstance()?.appContext.provides || getCurrentApp()._context.provides - - provides[key] = value -}) as typeof vueProvide +}) as unknown as typeof vueInject diff --git a/packages/ui/src/services/global-config/global-config.ts b/packages/ui/src/services/global-config/global-config.ts index 991b90d892..2982688b86 100644 --- a/packages/ui/src/services/global-config/global-config.ts +++ b/packages/ui/src/services/global-config/global-config.ts @@ -1,18 +1,19 @@ import cloneDeep from 'lodash/cloneDeep.js' -import { Ref, ref } from 'vue' +import { ref, getCurrentInstance } from 'vue' import { GlobalConfig, GlobalConfigUpdater, PartialGlobalConfig, ProvidedGlobalConfig } from './types' import { getComponentsDefaultConfig } from '../component-config' import { getIconDefaultConfig } from '../icon' import { getColorDefaultConfig } from '../color' import { getI18nConfigDefaults } from '../i18n' import { getBreakpointDefaultConfig } from '../breakpoint' -import { inject, provide } from '../current-app' +import { getGlobalProperty } from '../vue-plugin/utils' +import { getCurrentApp, inject } from '../current-app' import { mergeDeep } from '../../utils/merge-deep' import { getColorsClassesDefaultConfig } from '../colors-classes' export const GLOBAL_CONFIG = Symbol('GLOBAL_CONFIG') -export const createGlobalConfig = (): ProvidedGlobalConfig => { +export const createGlobalConfig = () => { const globalConfig = ref({ colors: getColorDefaultConfig(), icons: getIconDefaultConfig(), @@ -26,7 +27,7 @@ export const createGlobalConfig = (): ProvidedGlobalConfig => { * TODO: if this try won't be success, may be remake to provide/inject */ routerComponent: undefined, - }) as Ref + }) const getGlobalConfig = (): GlobalConfig => globalConfig.value const setGlobalConfig = (updater: GlobalConfig | GlobalConfigUpdater) => { @@ -47,6 +48,16 @@ export const createGlobalConfig = (): ProvidedGlobalConfig => { } } +const provideForCurrentApp = (provide: T) => { + const provides = getCurrentInstance()?.appContext.provides || getCurrentApp()?._context.provides + + if (!provides) { throw new Error('Vue app not found for provide') } + + provides[GLOBAL_CONFIG] = provide + + return provide +} + /** Use this function if you don't want to throw error if hook used outside setup function by useGlobalConfig */ export function useGlobalConfig () { let injected = inject(GLOBAL_CONFIG) as ProvidedGlobalConfig @@ -54,7 +65,7 @@ export function useGlobalConfig () { if (!injected) { injected = createGlobalConfig() - provide(GLOBAL_CONFIG, injected) + provideForCurrentApp(injected) } return injected diff --git a/packages/ui/src/utils/component-options/types.ts b/packages/ui/src/utils/component-options/types.ts index 617bc3fe02..c3071b11a8 100644 --- a/packages/ui/src/utils/component-options/types.ts +++ b/packages/ui/src/utils/component-options/types.ts @@ -22,7 +22,7 @@ declare type ExtractDefineComponentPropsType = true extends boolean ? { export type ExtractComponentProps = true extends boolean ? ExtractDefineComponentPropsType : never export type ExtractComponentEmits = T extends ComponentOptionsBase ? E: [] -export type ExtractComponentPropTypes = - T extends (props: infer P, ...args: any) => any ? P : - T extends new () => { $props: infer P } ? NonNullable

: - {} +type UnPropType = T extends PropType ? P : never +export type ExtractComponentPropTypes = { + [K in keyof ExtractComponentProps]: UnPropType[K]['type']> +}