quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
120 lines (91 loc) • 2.8 kB
JavaScript
import { h, ref, onUnmounted, Teleport } from 'vue'
import { noop } from '../../utils/event.js'
import { addFocusWaitFlag, removeFocusWaitFlag } from '../../utils/private/focus-manager.js'
import { createGlobalNode, removeGlobalNode } from '../../utils/private/global-nodes.js'
import { portalProxyList } from '../../utils/private/portal.js'
import { injectProp } from '../../utils/private/inject-obj-prop.js'
function isOnGlobalDialog (vm) {
vm = vm.parent
while (vm !== void 0 && vm !== null) {
if (vm.type.name === 'QGlobalDialog') {
return true
}
if (vm.type.name === 'QDialog' || vm.type.name === 'QMenu') {
return false
}
vm = vm.parent
}
return false
}
// Warning!
// You MUST specify "inheritAttrs: false" in your component
export default function (vm, innerRef, renderPortalContent, type) {
// showing, including while in show/hide transition
const portalIsActive = ref(false)
// showing & not in any show/hide transition
const portalIsAccessible = ref(false)
if (__QUASAR_SSR_SERVER__) {
return {
portalIsActive,
portalIsAccessible,
showPortal: noop,
hidePortal: noop,
renderPortal: noop
}
}
let portalEl = null
const focusObj = {}
const onGlobalDialog = type === 'dialog' && isOnGlobalDialog(vm)
function showPortal (isReady) {
if (isReady === true) {
removeFocusWaitFlag(focusObj)
portalIsAccessible.value = true
return
}
portalIsAccessible.value = false
if (portalIsActive.value === false) {
if (onGlobalDialog === false && portalEl === null) {
portalEl = createGlobalNode(false, type)
}
portalIsActive.value = true
// register portal
portalProxyList.push(vm.proxy)
addFocusWaitFlag(focusObj)
}
}
function hidePortal (isReady) {
portalIsAccessible.value = false
if (isReady !== true) { return }
removeFocusWaitFlag(focusObj)
portalIsActive.value = false
// unregister portal
const index = portalProxyList.indexOf(vm.proxy)
if (index !== -1) {
portalProxyList.splice(index, 1)
}
if (portalEl !== null) {
removeGlobalNode(portalEl)
portalEl = null
}
}
onUnmounted(() => { hidePortal(true) })
// needed for portal vm detection
vm.proxy.__qPortal = true
// public way of accessing the rendered content
injectProp(vm.proxy, 'contentEl', () => innerRef.value)
return {
showPortal,
hidePortal,
portalIsActive,
portalIsAccessible,
renderPortal: () => (
onGlobalDialog === true
? renderPortalContent()
: (
portalIsActive.value === true
? [ h(Teleport, { to: portalEl }, renderPortalContent()) ]
: void 0
)
)
}
}