Skip to content

Commit 6ffa690

Browse files
Gregor WoiwodeGregOnNet
authored andcommitted
feat(modal): use signals instead of exposing functions
1 parent d3219bd commit 6ffa690

File tree

3 files changed

+40
-66
lines changed

3 files changed

+40
-66
lines changed

apps/website/src/routes/docs/headless/(components)/modal/examples.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { component$, Signal, Slot, useSignal } from '@builder.io/qwik';
22
import { PreviewCodeExample } from '../../../_components/preview-code-example/preview-code-example';
3-
import { Modal, ModalApi, ModalContent, ModalHeader } from '@qwik-ui/headless';
3+
import { Modal, ModalContent, ModalHeader } from '@qwik-ui/headless';
44

55
export const Example01 = component$(() => {
6-
const modalApi: Signal<ModalApi | undefined> = useSignal();
6+
const openSig: Signal = useSignal(false);
77

88
return (
99
<PreviewCodeExample>
1010
<div q:slot="actualComponent">
11-
<button onClick$={() => modalApi.value?.open$()}>Open Modal</button>
11+
<button onClick$={() => (openSig.value = true)}>Open Modal</button>
1212

13-
<Modal api={modalApi}>
13+
<Modal open={openSig}>
1414
<ModalHeader>
1515
<h2>Hi 👋🏻</h2>
1616
</ModalHeader>

packages/kit-headless/src/components/modal/modal.spec.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { component$, useSignal } from '@builder.io/qwik';
22
import { mount } from 'cypress-ct-qwik';
33
import { Modal } from './modal';
4-
import { ModalApi } from './types';
54
import { ModalHeader } from './modal-header';
65
import { ModalContent } from './modal-content';
76
import { ModalFooter } from './modal-footer';
@@ -11,20 +10,20 @@ import { ModalFooter } from './modal-footer';
1110
* Reference: https://en.wikipedia.org/wiki/System_under_test
1211
*/
1312
const Sut = component$(() => {
14-
const modalApi = useSignal<ModalApi>();
13+
const openSig = useSignal(false);
1514
return (
1615
<>
17-
<button onClick$={() => modalApi.value?.open$()}>Open Dialog</button>
16+
<button onClick$={() => (openSig.value = true)}>Open Dialog</button>
1817

19-
<Modal api={modalApi}>
18+
<Modal open={openSig}>
2019
<ModalHeader>
2120
<h2>Hello 👋</h2>
2221
</ModalHeader>
2322
<ModalContent>I am a simple Modal</ModalContent>
2423
<ModalFooter>
2524
<button
2625
data-test="dialog-close-button"
27-
onClick$={() => modalApi.value?.close$()}
26+
onClick$={() => (openSig.value = false)}
2827
>
2928
Close Dialog
3029
</button>

packages/kit-headless/src/components/modal/modal.tsx

Lines changed: 32 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
$,
33
component$,
4+
QRL,
45
QwikIntrinsicElements,
56
QwikMouseEvent,
67
Signal,
@@ -10,7 +11,6 @@ import {
1011
useTask$
1112
} from '@builder.io/qwik';
1213
import styles from './modal-root.css?inline';
13-
import { ModalApi } from './types';
1414
import { isServer } from '@builder.io/qwik/build';
1515

1616
/**
@@ -23,89 +23,64 @@ import { isServer } from '@builder.io/qwik/build';
2323
* [ ] Think about more tests
2424
*/
2525

26-
export type ModalProps = QwikIntrinsicElements['dialog'] & {
27-
fullScreen?: boolean;
28-
api?: Signal<ModalApi | undefined>;
26+
export type ModalProps = Omit<QwikIntrinsicElements['dialog'], 'open'> & {
27+
open: Signal<boolean>;
28+
29+
fullScreen?: Signal<boolean>;
30+
31+
onOpen$?: QRL<() => void>;
32+
onClose$?: QRL<() => void>;
2933
};
3034

3135
export const Modal = component$((props: ModalProps) => {
3236
useStylesScoped$(styles);
3337

3438
/** Contains reference to the rendered HTMLDialogElement. */
35-
const dialogElementSig = useSignal<HTMLDialogElement>();
39+
const refSig = useSignal<HTMLDialogElement>();
3640

3741
/** Indicates whether the modal is open. */
38-
const isOpenSig = useSignal(false);
39-
40-
const open$ = $(() => {
41-
const dialog = dialogElementSig.value;
42+
const openSig = props.open;
4243

43-
if (!dialog) return;
44+
const closeOnBackdropClick$ = $(
45+
(event: QwikMouseEvent<HTMLDialogElement, MouseEvent>) => {
46+
if (hasDialogBackdropBeenClicked(event)) {
47+
openSig.value = false;
48+
}
49+
}
50+
);
4451

45-
dialog.showModal();
46-
isOpenSig.value = true;
47-
});
52+
/** Open or close Modal depending on its state. */
53+
useTask$(async ({ track }) => {
54+
const isOpen = track(() => openSig.value);
4855

49-
const close$ = $(() => {
50-
const dialog = dialogElementSig.value;
56+
const dialog = refSig.value;
5157

5258
if (!dialog) return;
5359

54-
dialog.close();
55-
isOpenSig.value = false;
56-
});
57-
58-
const closeOnBackdropClick$ = $(
59-
(event: QwikMouseEvent<HTMLDialogElement, MouseEvent>) =>
60-
hasDialogBackdropBeenClicked(event) ? close$() : Promise.resolve()
61-
);
62-
63-
/**
64-
*
65-
* Share the public API of the Modal if the modal-caller is interested.
66-
*
67-
*/
68-
useTask$(() => {
69-
if (!props.api) return;
70-
71-
props.api.value = { isOpen: isOpenSig, open$, close$ };
60+
if (isOpen) {
61+
dialog.showModal();
62+
await props.onOpen$?.();
63+
} else {
64+
await props.onClose$?.();
65+
dialog.close();
66+
}
7267
});
7368

74-
/**
75-
*
76-
* Lock Scrolling on page when Modal is opened.
77-
*
78-
*/
69+
/** Lock Scrolling on page when Modal is opened. */
7970
useTask$(({ track }) => {
8071
if (isServer) return;
8172

82-
const isOpened = track(() => isOpenSig.value);
73+
const isOpened = track(() => openSig.value);
8374

8475
window.document.body.style.overflow = isOpened ? 'hidden' : '';
8576
});
8677

87-
/**
88-
*
89-
* When modal is closed by pressing the Escape-Key,
90-
* we set the opened state to false.
91-
*
92-
*/
93-
useTask$(() => {
94-
if (isServer) return;
95-
96-
const dialog = dialogElementSig.value;
97-
98-
if (!dialog) return;
99-
100-
dialog.addEventListener('close', () => (isOpenSig.value = false));
101-
});
102-
10378
return (
10479
<dialog
105-
{...props}
10680
class={`${props.class} ${props.fullScreen ? 'full-screen' : ''}`}
107-
ref={dialogElementSig}
81+
ref={refSig}
10882
onClick$={closeOnBackdropClick$}
83+
onClose$={() => (openSig.value = false)}
10984
>
11085
<Slot />
11186
</dialog>

0 commit comments

Comments
 (0)