Open
Description
Champion
What's the motivation for this proposal?
Problems you are trying to solve:
- I want to start listening on event outside of
document
,window
orHTMLElement
without downloading core. - I want to cleanup listener that started within a
useOn
.
Goals you are trying to achieve:
Wrap Browser based event emitter, without downloading core right away.
Examples:
// wrap navigation.addEventListener('navigate', ...);
useNavigation('navigate', $(event => ...));
// wrap matchMedia('(min-width: 600px)').addEventListener('change', ...)
useMatchMedia('(min-width: 600px)', $(event => ...))
Any other context or information you want to share:
useOn
is the best place to achieve that, but it doesn't cleanup, so we need a way to know when the component is unmounted to cleanup.
Proposed Solution / Feature
What do you propose?
Emit a new CustomEvent before the component unmount.
Code examples
- When component is visible, start listeneing on 'navigate' without downloading core.
- When the event is triggers, it's forwarded to document.
- When document receive event, trigger the logic from the QRL
const useNavigation = (eventName: string, cb: QRL<(event: Event, element: Element) => any>) => {
useOnDocument('<custom-event>', cb);
useOn('qVisible', _qrlSync(
(e, el) => {
const handler = (event) => document.dispatchEvent(new CustomEvent('<custom-event>', {detail:event}));
navigation.addEventListener(eventName, handler);
el.addEventListener('qCleanup', () => navigation.removeEventListener(eventName, handler), { once: true });
},
`(e, el) => {
const handler = (event) => document.dispatchEvent(new CustomEvent('<custom-event>', {detail:event}));
navigation.addEventListener('${eventName}', handler);
el.addEventListener('qCleanup', () => navigation.removeEventListener('${eventName}', handler), { once: true });
}`,
));
};
The goal here is to
- not dowload core too early.
- not adding too much logic in the inline script (addEventListener and removeEventListener).
- make sure all event listeners are removed when the component is removed.
Additional information
The qCleanup
event should not impact the rendering process (shouldn't wait for the callbacks to fullfil)
In an ideal world the element should be still in the DOM when the event is received. But it's not mandatory for this RFC:
useOn('qCleanup', $(async (ev, el) => {
console.log(el.isConnected); // Ideally this should be true, but not mandatory
await new Promise((res) => setTimeout(res, 100));
console.log(el.isConnected); // This should be false
})
Another usage of this event would be to run ViewTransition on leaving element (But it would only work if the el is still in the DOM at this moment...)
useOn('qCleanup', $(async (ev, el) => {
const name = `_${Math.random()}_`;
el.style.viewTransitionName = name;
const transition = startViewTransition(() => {
return new Promise((res) => getPlatform().nextTick(res));
});
await transition.ready;
document.documentElement.animate({ opacity: 0 }, {
pseudoElement: `view-transition-old(${name})`,
duration: 100
})
}))
PRs/ Links / References
No response
Metadata
Metadata
Assignees
Labels
Remove this label when implementation is completeRemove this label when tests are verified to cover the implementationRemove this label when all critical discussions are resolved on the issueRemove this label when the necessary documentation for the feature / change is addedRemove this label when at least 2 core team members reviewed and approved the RFC implementation
Type
Projects
Status
In Progress (STAGE 2)