diff --git a/client.d.ts b/client.d.ts index 01d734ef3..6e20f5103 100644 --- a/client.d.ts +++ b/client.d.ts @@ -47,6 +47,7 @@ declare module 'vue-router/auto' { export { DataLoaderPlugin, NavigationResult, + useIsDataLoading } from 'unplugin-vue-router/data-loaders' // must be added to the virtual vue-router/auto // FIXME: is there a way to achieve this without losing the types? diff --git a/src/data-loaders/entries/index.ts b/src/data-loaders/entries/index.ts index 44e7b88c2..142d633cf 100644 --- a/src/data-loaders/entries/index.ts +++ b/src/data-loaders/entries/index.ts @@ -13,7 +13,11 @@ export type { export { toLazyValue } from '../createDataLoader' // new data fetching -export { DataLoaderPlugin, NavigationResult } from '../navigation-guard' +export { + DataLoaderPlugin, + NavigationResult, + useIsDataLoading, +} from '../navigation-guard' export type { DataLoaderPluginOptions, SetupLoaderGuardOptions, diff --git a/src/data-loaders/navigation-guard.ts b/src/data-loaders/navigation-guard.ts index 076b09f20..3f157186b 100644 --- a/src/data-loaders/navigation-guard.ts +++ b/src/data-loaders/navigation-guard.ts @@ -18,6 +18,7 @@ import type { } from 'vue-router' import { type _Awaitable } from '../utils' import { toLazyValue, type UseDataLoader } from './createDataLoader' +import { shallowRef, watch } from 'vue' /** * TODO: export functions that allow preloading outside of a navigation guard @@ -414,3 +415,35 @@ export interface DataLoaderPluginOptions { */ errors?: Array any> | ((reason?: unknown) => boolean) } + +export function useIsDataLoading(router: Router) { + const isLoading = shallowRef(false) + + watch( + () => { + // read the current route + const currentRoute = router.currentRoute.value + if (!currentRoute) { + return [] + } + + // extract the loaders from route meta + const loaders = currentRoute.meta[LOADER_SET_KEY] || new Set() + + // map each loader to its isLoading.value + return Array.from(loaders).map((loader) => { + const entry = loader._.getEntry(router) + return entry?.isLoading.value ?? false + }) + }, + (loaderStates) => { + // if any loader is true, isLoading becomes true + isLoading.value = loaderStates.some((state) => state) + }, + { + immediate: true, + } + ) + + return isLoading +}