import { isRef, onScopeDispose, watch } from 'vue' import { computed } from '@vue/reactivity' import { isClient } from '@vueuse/core' import { addClass, getScrollBarWidth, getStyle, hasClass, removeClass, throwError, } from '@element-plus/utils' import { useNamespace } from '../use-namespace' import type { Ref } from 'vue' /** * Hook that monitoring the ref value to lock or unlock the screen. * When the trigger became true, it assumes modal is now opened and vice versa. * @param trigger {Ref} */ export const useLockscreen = (trigger: Ref) => { if (!isRef(trigger)) { throwError( '[useLockscreen]', 'You need to pass a ref param to this function' ) } const ns = useNamespace('popup') const hiddenCls = computed(() => ns.bm('parent', 'hidden')) if (!isClient || hasClass(document.body, hiddenCls.value)) { return } let scrollBarWidth = 0 let withoutHiddenClass = false let bodyPaddingRight = '0' let computedBodyPaddingRight = 0 const cleanup = () => { removeClass(document.body, hiddenCls.value) if (withoutHiddenClass) { document.body.style.paddingRight = bodyPaddingRight } } watch(trigger, (val) => { if (!val) { cleanup() return } withoutHiddenClass = !hasClass(document.body, hiddenCls.value) if (withoutHiddenClass) { bodyPaddingRight = document.body.style.paddingRight computedBodyPaddingRight = Number.parseInt( getStyle(document.body, 'paddingRight'), 10 ) } scrollBarWidth = getScrollBarWidth(ns.namespace.value) const bodyHasOverflow = document.documentElement.clientHeight < document.body.scrollHeight const bodyOverflowY = getStyle(document.body, 'overflowY') if ( scrollBarWidth > 0 && (bodyHasOverflow || bodyOverflowY === 'scroll') && withoutHiddenClass ) { document.body.style.paddingRight = `${ computedBodyPaddingRight + scrollBarWidth }px` } addClass(document.body, hiddenCls.value) }) onScopeDispose(() => cleanup()) }