Skip to content

Commit 05354a4

Browse files
committed
♿️ Prevent scrolling of main content when modal or sheet are active
1 parent 5094067 commit 05354a4

File tree

5 files changed

+76
-29
lines changed

5 files changed

+76
-29
lines changed

astro.config.mjs.timestamp-1734374756635-978b266bfa22.mjs

Lines changed: 0 additions & 29 deletions
This file was deleted.

scripts/utilityTypes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ export type Toast = {
124124
}
125125
126126
declare module 'webcoreui' {
127+
export const bodyFreeze: (freeze: boolean) => void
127128
export const classNames: (classes: any[]) => string
128129
129130
export const setCookie: (name: string, value: string, days: number) => void

src/tests/bodyFreeze.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { bodyFreeze } from '@utils/bodyFreeze'
2+
3+
import {
4+
afterEach,
5+
beforeEach,
6+
describe,
7+
expect,
8+
it,
9+
vi
10+
} from 'vitest'
11+
12+
describe('bodyFreeze', () => {
13+
beforeEach(() => {
14+
document.body.style.paddingRight = ''
15+
document.body.style.overflow = ''
16+
17+
vi.spyOn(window, 'innerWidth', 'get').mockReturnValue(1024)
18+
Object.defineProperty(document.body, 'clientWidth', {
19+
configurable: true,
20+
get: vi.fn(() => 1000)
21+
})
22+
})
23+
24+
afterEach(() => {
25+
vi.restoreAllMocks()
26+
27+
document.body.style.paddingRight = ''
28+
document.body.style.overflow = ''
29+
})
30+
31+
it('should freeze the body (hide overflow and set padding)', () => {
32+
bodyFreeze(true)
33+
34+
expect(document.body.style.overflow).toBe('hidden')
35+
expect(document.body.style.paddingRight).toBe('24px') // 1024 - 1000 = 24
36+
})
37+
38+
it('should unfreeze the body (reset styles) when freeze is false', () => {
39+
bodyFreeze(true)
40+
expect(document.body.style.overflow).toBe('hidden')
41+
42+
bodyFreeze(false)
43+
44+
expect(document.body.style.overflow).toBe('')
45+
expect(document.body.style.paddingRight).toBe('')
46+
})
47+
48+
it('should freeze the body by default when no arguments are passed', () => {
49+
bodyFreeze()
50+
51+
expect(document.body.style.overflow).toBe('hidden')
52+
expect(document.body.style.paddingRight).toBe('24px')
53+
})
54+
})

src/utils/bodyFreeze.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export const bodyFreeze = (freeze = true) => {
2+
const scrollbarWidth = window.innerWidth - document.body.clientWidth
3+
4+
if (freeze) {
5+
document.body.style.paddingRight = `${scrollbarWidth}px`
6+
document.body.style.overflow = 'hidden'
7+
} else {
8+
document.body.style.paddingRight = ''
9+
document.body.style.overflow = ''
10+
}
11+
}

src/utils/modal.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { bodyFreeze } from './bodyFreeze'
2+
13
export type ModalCallback = {
24
trigger: Element | null
35
modal: HTMLElement
@@ -33,6 +35,8 @@ export const modal = (config: Modal | string) => {
3335
const listener = () => {
3436
modalDOM.dataset.show = ''
3537

38+
bodyFreeze(false)
39+
3640
onClose?.({
3741
trigger: triggerDOM,
3842
modal: modalDOM
@@ -50,6 +54,8 @@ export const modal = (config: Modal | string) => {
5054
if (modalDOM.dataset.show && event.key === 'Escape') {
5155
modalDOM.dataset.show = ''
5256

57+
bodyFreeze(false)
58+
5359
onClose?.({
5460
trigger: triggerDOM,
5561
modal: modalDOM
@@ -70,6 +76,8 @@ export const modal = (config: Modal | string) => {
7076
const listener = () => {
7177
modalDOM.dataset.show = ''
7278

79+
bodyFreeze(false)
80+
7381
onClose?.({
7482
trigger: triggerDOM,
7583
modal: modalDOM
@@ -86,6 +94,8 @@ export const modal = (config: Modal | string) => {
8694
const handleOpen = () => {
8795
modalDOM.dataset.show = 'true'
8896

97+
bodyFreeze()
98+
8999
onOpen?.({
90100
trigger: triggerDOM,
91101
modal: modalDOM

0 commit comments

Comments
 (0)