fix: close modal

This commit is contained in:
Dominik Pschenitschni 2022-11-22 17:45:22 +01:00
parent b264065d7e
commit 345542cbbd
Signed by: dpschen
GPG Key ID: B257AC0149F43A77
5 changed files with 109 additions and 60 deletions

View File

@ -5,12 +5,7 @@ export default { inheritAttrs: false }
</script>
<script setup lang="ts">
import { useAttrs } from 'vue'
defineProps<{ is: any }>()
const attrs = useAttrs()
console.log(JSON.parse(JSON.stringify(attrs)))
</script>
<template>

View File

@ -32,16 +32,14 @@
<quick-actions/>
<router-view :route="routeWithModal" v-slot="{ Component }">
<keep-alive :include="['list.list', 'list.gantt', 'list.table', 'list.kanban']">
<router-view v-if="routeWithModal" :route="routeWithModal" v-slot="{ Component }">
<!-- <keep-alive :include="['list.list', 'list.gantt', 'list.table', 'list.kanban']"> -->
<component :is="Component"/>
</keep-alive>
<!-- test -->
<!-- </keep-alive> -->
</router-view>
<component
:is="currentModal"
@close="closeModal()"
/>
<component :is="currentModal" />
<BaseButton
class="keyboard-shortcuts-button d-print-none"
@ -69,7 +67,7 @@ import {useLabelStore} from '@/stores/labels'
import {useRouteWithModal} from '@/composables/useRouteWithModal'
import {useRenewTokenOnFocus} from '@/composables/useRenewTokenOnFocus'
const {routeWithModal, currentModal, closeModal} = useRouteWithModal()
const {routeWithModal, currentModal} = useRouteWithModal()
const baseStore = useBaseStore()
const background = computed(() => baseStore.background)

View File

@ -1,56 +1,112 @@
import { computed, shallowRef, watchEffect, h, type VNode } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { computed, shallowRef, watch, h, type VNode, ref } from 'vue'
import { useRoute, useRouter, loadRouteLocation, type RouteLocationNormalizedLoaded, type RouteLocationRaw } from 'vue-router'
import router from '@/router'
// this is adapted from vue-router
// https://github.com/vuejs/vue-router-next/blob/798cab0d1e21f9b4d45a2bd12b840d2c7415f38a/src/RouterView.ts#L125
function getRouteProps(route: RouteLocationNormalizedLoaded) {
const routePropsOption = route.matched[0]?.props.default
return routePropsOption
? routePropsOption === true
? route.params
: typeof routePropsOption === 'function'
? routePropsOption(route)
: routePropsOption
: {}
}
function resolveAndLoadRoute(route: RouteLocationRaw) {
return loadRouteLocation(router.resolve(route))
}
export function useRouteWithModal() {
const router = useRouter()
const route = useRoute()
const backdropView = computed(() => route.fullPath && window.history.state.backdropView)
const routeWithModal = computed(() => {
return backdropView.value
? router.resolve(backdropView.value)
: route
const backdropView = computed<RouteLocationRaw | undefined>(() => {
// every time the fullPath changes we check the history state
// this happens also initially
return route.fullPath
? window.history.state?.backdropView
: undefined
})
const routerIsReady = ref(false)
router.isReady().then(() => {
routerIsReady.value = true
})
const baseRoute = shallowRef<RouteLocationNormalizedLoaded>()
watch(
[backdropView, routerIsReady],
async () => {
if (routerIsReady.value === false || !route.fullPath) {
return
}
if (backdropView.value === undefined) {
if (route.meta?.showAsModal !== true) {
baseRoute.value = route
return
}
// TODO: maybe load parent route here in the future,
// via: route.matched[route.matched.length - 2]
// see: https://router.vuejs.org/guide/migration/#removal-of-parent-from-route-locations
baseRoute.value = await resolveAndLoadRoute({ name: 'home' })
return
}
// we get the resolved route from the fullpath
// and wait for the route component to be loaded before we assign it
baseRoute.value = await resolveAndLoadRoute(backdropView.value)
},
{immediate: true},
)
const backdropRoute = computed(() => route.fullPath !== baseRoute.value?.fullPath ? baseRoute.value : undefined)
const currentModal = shallowRef<VNode>()
watchEffect(() => {
if (!backdropView.value) {
currentModal.value = undefined
return
watch(
[backdropRoute, baseRoute, route],
() => {
if (routerIsReady.value === false || !route.fullPath || !backdropRoute.value) {
currentModal.value = undefined
return
}
const props = getRouteProps(route)
props.backdropView = backdropRoute.value
props.onClose = closeModal
const component = route.matched[0]?.components?.default
if (!component) {
currentModal.value = undefined
return
}
currentModal.value = h(component, props)
},
{immediate: true},
)
async function closeModal() {
await router.isReady()
if (backdropRoute.value !== undefined) {
// TODO: Dialog modals might want to replace the route here via router.replace()
return router.push(backdropRoute.value)
}
// this is adapted from vue-router
// https://github.com/vuejs/vue-router-next/blob/798cab0d1e21f9b4d45a2bd12b840d2c7415f38a/src/RouterView.ts#L125
const routePropsOption = route.matched[0]?.props.default
const routeProps = routePropsOption
? routePropsOption === true
? route.params
: typeof routePropsOption === 'function'
? routePropsOption(route)
: routePropsOption
: {}
routeProps.backdropView = backdropView.value
const component = route.matched[0]?.components?.default
if (!component) {
currentModal.value = undefined
return
}
currentModal.value = h(component, routeProps)
})
function closeModal() {
const historyState = computed(() => route.fullPath && window.history.state)
if (historyState.value === undefined) {
router.back()
if (window.history.state === undefined) {
return router.push({ name: 'home' })
} else {
const backdropRoute = historyState.value.backdropView && router.resolve(historyState.value.backdropView)
router.push(backdropRoute)
router.back()
throw new Error('')
}
}
return {routeWithModal, currentModal, closeModal}
return {
routeWithModal: baseRoute,
currentModal,
closeModal,
}
}

View File

@ -240,7 +240,7 @@ const router = createRouter({
meta: {
showAsModal: true,
},
props: route => ({ namespaceId: parseInt(route.params.id as string) }),
props: route => ({ namespaceId: Number(route.params.id as string) }),
},
{
path: '/namespaces/:id/settings/delete',
@ -468,6 +468,9 @@ const router = createRouter({
path: '/about',
name: 'about',
component: About,
meta: {
showAsModal: true,
},
},
],
})

View File

@ -512,9 +512,6 @@ const props = defineProps({
},
})
defineEmits(['close'])
const attrs = useAttrs()
console.log(JSON.parse(JSON.stringify(attrs)))
const router = useRouter()
const {t} = useI18n({useScope: 'global'})