Skip to content
This repository was archived by the owner on Jan 9, 2022. It is now read-only.

Commit 346d882

Browse files
committed
feat: replace body-scroll-lock by own implementation
1 parent 0098dac commit 346d882

File tree

6 files changed

+120
-46
lines changed

6 files changed

+120
-46
lines changed

package.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@
1515
"url": "https://github.com/MichaelGitArt/gitart-vue-dialog.git"
1616
},
1717
"license": "MIT",
18-
"dependencies": {
19-
"body-scroll-lock": "^4.0.0-beta.0"
20-
},
2118
"devDependencies": {
22-
"@types/body-scroll-lock": "^2.6.2",
2319
"@types/node": "^16.3.1",
2420
"@typescript-eslint/eslint-plugin": "^4.28.4",
2521
"@typescript-eslint/parser": "^4.28.4",

src/components/GDialog.vue

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<template v-if="activatedOnce">
33
<Teleport to="body">
44
<GDialogOverlay
5+
ref="overlay"
56
:active="isActive"
67
:deactivating="deactivating"
78
:active-z-index="activeZIndex"
@@ -11,7 +12,7 @@
1112
<Transition name="dialog-transition">
1213
<div
1314
v-show="isActive"
14-
ref="frame"
15+
ref="contentFrame"
1516
:class="classes"
1617
:style="styles"
1718
>
@@ -32,13 +33,12 @@
3233

3334
<script lang="ts">
3435
import {
35-
defineComponent, computed, ref, watch,
36+
defineComponent, computed, ref, watch, onBeforeUnmount,
3637
} from 'vue'
3738
3839
import { useStackable } from '../composable/stackable'
3940
import { useLazyActivation } from '../composable/lazyActivation'
40-
41-
import { disableScroll, enableScroll } from '../helper/scroll.helper'
41+
import { useScroll } from '../composable/scroll'
4242
4343
import GDialogOverlay from './GDialogOverlay.vue'
4444
import GDialogContent from './GDialogContent.vue'
@@ -120,6 +120,11 @@ export default defineComponent({
120120
emits: ['update:modelValue'],
121121
122122
setup(props, { emit }) {
123+
const contentFrame = ref<Element>()
124+
const overlay = ref<InstanceType<typeof GDialogOverlay>>()
125+
126+
const overlayElement = computed<Element | undefined>(() => overlay.value?.$el as Element)
127+
123128
const onClickOutside = () => {
124129
if (!props.persistent) {
125130
emit('update:modelValue', false)
@@ -130,12 +135,11 @@ export default defineComponent({
130135
computed(() => props.modelValue),
131136
)
132137
133-
const frame = ref(null)
134138
const { activeZIndex } = useStackable({
135139
activeElSelector: '.q-dialog-frame--active',
136140
stackMinZIndex: 200,
137141
isActive,
138-
content: frame,
142+
content: contentFrame,
139143
})
140144
141145
const classes = computed(() => [
@@ -149,14 +153,23 @@ export default defineComponent({
149153
zIndex: activeZIndex.value,
150154
}))
151155
156+
const { enableScroll, disableScroll } = useScroll({
157+
overlay: overlayElement,
158+
content: contentFrame,
159+
})
160+
152161
watch(isActive, (active) => {
153162
if(active) {
154-
disableScroll(props.hideScrollbar)
163+
disableScroll()
155164
} else {
156165
enableScroll()
157166
}
158167
})
159168
169+
onBeforeUnmount(() => {
170+
enableScroll()
171+
})
172+
160173
return {
161174
onClickOutside,
162175
activatedOnce,
@@ -165,7 +178,8 @@ export default defineComponent({
165178
deactivating,
166179
classes,
167180
styles,
168-
frame,
181+
contentFrame,
182+
overlay,
169183
}
170184
},
171185
})

src/composable/scroll.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { Ref } from 'vue'
2+
3+
import { noScrollableParent } from '../helper/scroll.helper'
4+
5+
type ScrollParams = {
6+
overlay: Ref<Element | undefined>
7+
content: Ref<Element | undefined>
8+
}
9+
10+
export const useScroll = ({
11+
overlay,
12+
content,
13+
}: ScrollParams) => {
14+
let disabled = false
15+
16+
const eventListener = (event: WheelEvent) => {
17+
if(event.target === overlay.value
18+
|| event.target === document.body
19+
|| noScrollableParent(event, content.value)
20+
) {
21+
event.preventDefault()
22+
}
23+
}
24+
25+
const disableScroll = () => {
26+
if(disabled) {
27+
return
28+
}
29+
30+
window.addEventListener('wheel', eventListener, {
31+
passive: false,
32+
})
33+
disabled = true
34+
}
35+
36+
const enableScroll = () => {
37+
if(!disabled) {
38+
return
39+
}
40+
41+
window.removeEventListener('wheel', eventListener)
42+
disabled = false
43+
}
44+
45+
return {
46+
disableScroll,
47+
enableScroll,
48+
}
49+
}

src/composable/stackable.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ interface IUseStackableParams {
99
activeElSelector: string
1010
stackMinZIndex: number
1111
isActive: Ref<boolean>
12-
content: Ref<Element | null>
12+
content: Ref<Element | undefined>
1313
}
1414

1515
export const useStackable: (param: IUseStackableParams) => {activeZIndex: ComputedRef<number>} = ({

src/helper/scroll.helper.ts

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,57 @@
1-
import { enableBodyScroll, disableBodyScroll } from 'body-scroll-lock'
1+
/**
2+
* A copy of the vuetify implemantation
3+
* https://github.com/vuetifyjs/vuetify/blob/v2.5.8/packages/vuetify/src/mixins/overlayable/index.ts
4+
*/
25

3-
export const getScrollbarWidth = () => {
4-
const container = document.createElement('div')
5-
container.style.visibility = 'hidden'
6-
container.style.overflow = 'scroll'
7-
const inner = document.createElement('div')
6+
/**
7+
* Polyfill for Event.prototype.composedPath
8+
*/
9+
const composedPath = (e: WheelEvent): EventTarget[] => {
10+
if (e.composedPath) return e.composedPath()
811

9-
container.appendChild(inner)
10-
document.body.appendChild(container)
11-
const scrollbarWidth = container.offsetWidth - inner.offsetWidth
12-
document.body.removeChild(container)
12+
const path = []
13+
let el = e.target as Element
1314

14-
return scrollbarWidth
15-
}
15+
while (el) {
16+
path.push(el)
17+
18+
if (el.tagName === 'HTML') {
19+
path.push(document)
20+
path.push(window)
1621

17-
export const disableScroll = (hideScrollbar = false) => {
18-
if (hideScrollbar) {
19-
disableBodyScroll(document.body)
20-
} else {
21-
const scrollWidth = getScrollbarWidth()
22-
disableBodyScroll(document.body)
23-
if (scrollWidth > 0) {
24-
document.body.style.paddingRight = scrollWidth + 'px'
22+
return path
2523
}
24+
25+
el = el.parentElement!
2626
}
27+
return path
2728
}
2829

29-
export const enableScroll = () => {
30-
enableBodyScroll(document.body)
31-
document.body.style.paddingRight = '0'
30+
const hasScrollbar = (el?: Element) => {
31+
if (!el || el.nodeType !== Node.ELEMENT_NODE) return false
32+
33+
const style = window.getComputedStyle(el)
34+
return ['auto', 'scroll'].includes(style.overflowY!) && el.scrollHeight > el.clientHeight
35+
}
36+
37+
const shouldScroll = (el: Element, delta: number) => {
38+
if (el.scrollTop === 0 && delta < 0) return true
39+
return el.scrollTop + el.clientHeight === el.scrollHeight && delta > 0
40+
}
41+
42+
export const noScrollableParent = (event: WheelEvent, content: Element | undefined) => {
43+
const path = composedPath(event)
44+
const delta = event.deltaY
45+
46+
for (let index = 0; index < path.length; index++) {
47+
const el = path[index]
48+
49+
if (el === document) return true
50+
if (el === document.documentElement) return true
51+
if (el === content) return true
52+
53+
if (hasScrollbar(el as Element)) return shouldScroll(el as Element, delta)
54+
}
55+
56+
return true
3257
}

yarn.lock

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -292,11 +292,6 @@
292292
remark "^13.0.0"
293293
unist-util-find-all-after "^3.0.2"
294294

295-
"@types/body-scroll-lock@^2.6.2":
296-
version "2.6.2"
297-
resolved "https://registry.yarnpkg.com/@types/body-scroll-lock/-/body-scroll-lock-2.6.2.tgz#ce56d17e1bf8383c08a074733c4e9e536a59ae61"
298-
integrity sha512-PhoQPbwPYspXqf7lkwtF7aJzAwL88t+9E/e0b2X84tlHpU8ZuS9UNnLtkT0XhyZJYHpET5qRfIdZ0HBIxuc7HQ==
299-
300295
"@types/estree@^0.0.48":
301296
version "0.0.48"
302297
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.48.tgz#18dc8091b285df90db2f25aa7d906cfc394b7f74"
@@ -761,11 +756,6 @@ bluebird@^3.7.2:
761756
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
762757
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
763758

764-
body-scroll-lock@^4.0.0-beta.0:
765-
version "4.0.0-beta.0"
766-
resolved "https://registry.yarnpkg.com/body-scroll-lock/-/body-scroll-lock-4.0.0-beta.0.tgz#4f78789d10e6388115c0460cd6d7d4dd2bbc4f7e"
767-
integrity sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==
768-
769759
brace-expansion@^1.1.7:
770760
version "1.1.11"
771761
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"

0 commit comments

Comments
 (0)