Skip to content

Commit 89dc27f

Browse files
committed
fix(dialog): lock scrolling when dialog is opened
1 parent feb9c8d commit 89dc27f

File tree

5 files changed

+113
-18
lines changed

5 files changed

+113
-18
lines changed

packages/kit-headless/src/components/dialog/dialog.root.tsx

+18-10
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
} from '@builder.io/qwik';
1111
import { dialogContext } from './dialog.context';
1212
import { DialogContext, DialogState, RootProps } from './types';
13-
import { DialogRef } from './types/dialog-ref';
1413
import { hasDialogBackdropBeenClicked } from './utils';
1514

1615
export const Root = component$((props: RootProps) => {
@@ -67,16 +66,25 @@ export const Root = component$((props: RootProps) => {
6766

6867
useContextProvider(dialogContext, context);
6968

70-
/** Share public-api with its parent. */
71-
useVisibleTask$(() => {
72-
if (props.ref) {
73-
const dialogRef: DialogRef = {
74-
open$: context.open$,
75-
close$: context.close$,
76-
};
69+
useVisibleTask$(({ track }) => {
70+
const opened = track(() => state.opened);
7771

78-
props.ref.value = dialogRef;
79-
}
72+
// We only share the DialogRef if the dialog's parent is interested.
73+
if (!props.ref) return;
74+
75+
props.ref.value = {
76+
opened,
77+
open$: context.open$,
78+
close$: context.close$,
79+
};
80+
});
81+
82+
useVisibleTask$(({ track }) => {
83+
const opened = track(() => state.opened);
84+
85+
const overflow = opened ? 'hidden' : '';
86+
87+
window.document.body.style.overflow = overflow;
8088
});
8189

8290
return <Slot />;

packages/kit-headless/src/components/dialog/dialog.stories.tsx

+22
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,28 @@ export const FullScreen: Story = {
105105
},
106106
};
107107

108+
export const PageScrollBlocking: Story = {
109+
render: (props) => (
110+
<>
111+
<p>This page should not be scrollable, when the dialog is open</p>
112+
<Dialog.Root {...props}>
113+
<Dialog.Trigger>
114+
<button>Open Dialog</button>
115+
</Dialog.Trigger>
116+
<Dialog.Content>
117+
<p>Hello World</p>
118+
<Dialog.Actions>
119+
<Dialog.Close>
120+
<button>Close</button>
121+
</Dialog.Close>
122+
</Dialog.Actions>
123+
</Dialog.Content>
124+
</Dialog.Root>
125+
<div style="background-color: red; width: 50vw; height: 150vh"></div>
126+
</>
127+
),
128+
};
129+
108130
/**
109131
* Using a component$ here to be able to use `useSignal`.
110132
* useSignal cannot be used directly inside a story's render-Function.
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
import { DialogContext } from './dialog-context';
22

3-
export type DialogRef = Pick<DialogContext, 'open$' | 'close$'>;
3+
export type DialogRef = Pick<DialogContext, 'open$' | 'close$'> & {
4+
opened: boolean;
5+
};

packages/kit-headless/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export * from './components/carousel/use';
88
export * as Checkbox from './components/checkbox/checkbox';
99
export * from './components/collapse/collapse';
1010
export * as Dialog from './components/dialog/public_api';
11+
export type { DialogRef } from './components/dialog/types/dialog-ref';
1112
export * from './components/drawer';
1213
export * from './components/input-phone';
1314
export * as Input from './components/input/input';
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,79 @@
1-
import { Slot, component$ } from '@builder.io/qwik';
2-
import { Dialog } from '@qwik-ui/headless';
1+
import { Slot, component$, useComputed$, useSignal } from '@builder.io/qwik';
2+
import { Dialog, DialogRef } from '@qwik-ui/headless';
33

44
export const Root = component$((props: Dialog.RootProps) => {
5+
const dialog = useSignal<DialogRef>();
6+
7+
const modalClass = useComputed$(() => {
8+
const clazz = dialog.value?.opened ? 'modal modal-open' : 'modal';
9+
console.log('CHANGE', dialog.value?.opened, clazz);
10+
11+
return clazz;
12+
});
13+
514
return (
6-
<Dialog.Root class="bg-slate-900 rounded-md text-white" {...props}>
15+
<Dialog.Root class={modalClass.value} {...props} ref={dialog}>
716
<Slot />
817
</Dialog.Root>
918
);
1019
});
1120

12-
export const Trigger = Dialog.Trigger;
1321
export const Close = Dialog.Close;
22+
export const Trigger = Dialog.Trigger;
23+
24+
export const Content = component$(() => {
25+
return (
26+
<Dialog.Content>
27+
<div class="modal-box">
28+
<Slot />
29+
</div>
30+
</Dialog.Content>
31+
);
32+
});
33+
export const ContentTitle = component$(() => {
34+
return (
35+
<Dialog.ContentTitle>
36+
<h3 class="font-bold text-lg">
37+
<Slot />
38+
</h3>
39+
</Dialog.ContentTitle>
40+
);
41+
});
42+
export const ContentText = component$(() => {
43+
return (
44+
<Dialog.ContentText>
45+
<p class="py-4">
46+
<Slot />
47+
</p>
48+
</Dialog.ContentText>
49+
);
50+
});
51+
52+
export const Actions = component$(() => {
53+
return (
54+
<Dialog.Actions>
55+
<div class="modal-actions">
56+
<Slot />
57+
</div>
58+
</Dialog.Actions>
59+
);
60+
});
61+
62+
/*
63+
64+
<!-- The button to open modal -->
65+
<label for="my-modal" class="btn">open modal</label>
66+
67+
<!-- Put this part before </body> tag -->
68+
<input type="checkbox" id="my-modal" class="modal-toggle" />
69+
<div class="modal">
70+
<div class="modal-box">
71+
<h3 class="font-bold text-lg">Congratulations random Internet user!</h3>
72+
<p class="py-4">You've been selected for a chance to get one year of subscription to use Wikipedia for free!</p>
73+
<div class="modal-action">
74+
<label for="my-modal" class="btn">Yay!</label>
75+
</div>
76+
</div>
77+
</div>
1478
15-
export const Content = Dialog.Content;
16-
export const ContentTitle = Dialog.ContentTitle;
17-
export const ContentText = Dialog.ContentText;
79+
*/

0 commit comments

Comments
 (0)