nuxt
Version:
[](https://nuxt.com)
91 lines (90 loc) • 3.08 kB
JavaScript
import { Suspense, Transition, computed, defineComponent, h, inject, mergeProps, nextTick, onMounted, provide, ref, unref } from "vue";
import { _wrapIf } from "./utils.js";
import { useRoute } from "#app/composables/router";
import { useRoute as useVueRouterRoute } from "#build/pages";
import layouts from "#build/layouts";
import { appLayoutTransition as defaultLayoutTransition } from "#build/nuxt.config.mjs";
import { useNuxtApp } from "#app";
export const LayoutMetaSymbol = Symbol("layout-meta");
export default defineComponent({
name: "NuxtLayout",
inheritAttrs: false,
props: {
name: {
type: [String, Boolean, Object],
default: null
}
},
setup(props, context) {
const nuxtApp = useNuxtApp();
const injectedRoute = inject("_route");
const route = injectedRoute === useRoute() ? useVueRouterRoute() : injectedRoute;
const layout = computed(() => unref(props.name) ?? route.meta.layout ?? "default");
const layoutRef = ref();
context.expose({ layoutRef });
return () => {
const done = nuxtApp.deferHydration();
const hasLayout = layout.value && layout.value in layouts;
if (process.dev && layout.value && !hasLayout && layout.value !== "default") {
console.warn(`Invalid layout \`${layout.value}\` selected.`);
}
const transitionProps = route.meta.layoutTransition ?? defaultLayoutTransition;
return _wrapIf(Transition, hasLayout && transitionProps, {
default: () => h(Suspense, { suspensible: true, onResolve: () => {
nextTick(done);
} }, {
default: () => _wrapIf(LayoutProvider, hasLayout && {
layoutProps: mergeProps(context.attrs, { ref: layoutRef }),
key: layout.value,
name: layout.value,
shouldProvide: !props.name,
hasTransition: !!transitionProps
}, context.slots).default()
})
}).default();
};
}
});
const LayoutProvider = defineComponent({
name: "NuxtLayoutProvider",
inheritAttrs: false,
props: {
name: {
type: String
},
layoutProps: {
type: Object
},
hasTransition: {
type: Boolean
},
shouldProvide: {
type: Boolean
}
},
setup(props, context) {
if (props.shouldProvide) {
const name = props.name;
provide(LayoutMetaSymbol, {
isCurrent: (route) => name === (route.meta.layout ?? "default")
});
}
let vnode;
if (process.dev && process.client) {
onMounted(() => {
nextTick(() => {
if (["#comment", "#text"].includes(vnode?.el?.nodeName)) {
console.warn(`[nuxt] \`${props.name}\` layout does not have a single root node and will cause errors when navigating between routes.`);
}
});
});
}
return () => {
if (process.dev && process.client && props.hasTransition) {
vnode = h(layouts[props.name], props.layoutProps, context.slots);
return vnode;
}
return h(layouts[props.name], props.layoutProps, context.slots);
};
}
});