11import {
22 $ ,
33 component$ ,
4+ QRL ,
45 QwikIntrinsicElements ,
56 QwikMouseEvent ,
67 Signal ,
@@ -10,7 +11,6 @@ import {
1011 useTask$
1112} from '@builder.io/qwik' ;
1213import styles from './modal-root.css?inline' ;
13- import { ModalApi } from './types' ;
1414import { 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
3135export 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