In Qwik JS I am trying to create a modal that closes when Esc is pressed. The modal needs to be accessible from anywhere, so I put it in layout.tsx.
layout.tsx
import {component$, Slot, useStore} from '@builder.io/qwik';
import Header from '../components/header/header';
import Modal from '~/components/modal/modal';
export default component$(() => {
const store = useStore({
showModal: true,
});
return (
<>
<main>
<Header/>
<section>
<Slot/>
</section>
<button onclick$={() => store.showModal = true}>Show modal</button>
</main>
{
store.showModal
&& (
<Modal onClose={$(() => {
store.showModal = false;
})}>
foo
</Modal>
)
}
</>
);
});
I want to close the modal only when Esc is pressed, so the "keyup" callback first checks if Esc was pressed, then resolves the passed QRL, and then executes it.
modal.tsx
import {component$, QRL, Slot, useVisibleTask$} from '@builder.io/qwik';
export type Props = {
onClose: QRL<() => void>;
}
export default component$((props: Props) => {
useVisibleTask$(() => {
const onKeyUp = async (e: KeyboardEvent) => {
const key = (e as KeyboardEvent).key || (e as KeyboardEvent).code;
if (key === 'Escape') {
const cb = await props.onClose.resolve();
cb();
}
};
document.addEventListener('keyup', onKeyUp, true);
return () => {
document.removeEventListener('keyup', onKeyUp, true);
};
}, {
strategy: 'document-ready',
});
return (
<div class="modal-bg">
<div class="modal">
<Slot/>
</div>
</div>
);
});
However, this results in an error:
Error: Code(14): Invoking 'use*()' method outside of invocation context.
How do I get around this problem? How do I execute more than just the QRL callback that is passed?