diff --git a/source/one-event.md b/source/one-event.md index 85a54fb..b1acf40 100644 --- a/source/one-event.md +++ b/source/one-event.md @@ -17,11 +17,31 @@ It also supports filtering: import {oneEvent} from 'webext-events'; // Wait until the user opens a new tab, but it has it be HTTPS -await oneEvent(chrome.tabs.onCreated, (tab) => tab.pendingUrl?.startsWith('https')); +await oneEvent(chrome.tabs.onCreated, { + filter: (tab) => tab.pendingUrl?.startsWith('https'), +}); console.log('Hurray, a new HTTPS tab was created') ``` +And abort signals: + +```js +import {oneEvent} from 'webext-events'; + +// Wait until the user opens a new tab, but only for one second +const timeout = AbortSignal.timeout(1000); +await oneEvent(chrome.tabs.onCreated, { + signal: timeout, +}); + +if (timeout.aborted) { + console.log('No tab was created in time') +} else { + console.log('Hurray, a new tab was created') +} +``` + ## Compatibility - Any browser diff --git a/source/one-event.test.ts b/source/one-event.test.ts index bbe7cf4..d0377e8 100644 --- a/source/one-event.test.ts +++ b/source/one-event.test.ts @@ -33,7 +33,7 @@ describe('oneEvent', () => { expect(chrome.runtime.onMessage.hasListeners()).toBe(false); const eventPromise = oneEvent( chrome.runtime.onMessage, - ({greeting}) => greeting === 'sup', + {filter: ({greeting}) => greeting === 'sup'}, ); expect(chrome.runtime.onMessage.hasListeners()).toBe(true); @@ -47,22 +47,22 @@ describe('oneEvent', () => { }); it('it should resolve original event\'s parameters', () => { - void oneEvent(chrome.tabs.onMoved, (tabId, moveInfo) => { + void oneEvent(chrome.tabs.onMoved, {filter(tabId, moveInfo) { expectTypeOf(tabId).toEqualTypeOf(); expectTypeOf(moveInfo).toEqualTypeOf(); return true; - }); + }}); - void oneEvent(chrome.runtime.onMessage, (message, sender, sendResponse) => { + void oneEvent(chrome.runtime.onMessage, {filter(message, sender, sendResponse) { expectTypeOf(message).toEqualTypeOf(); expectTypeOf(sender).toEqualTypeOf(); expectTypeOf(sendResponse).toEqualTypeOf<(response?: any) => void>(); return true; - }); + }}); - void oneEvent(chrome.cookies.onChanged, changeInfo => { + void oneEvent(chrome.cookies.onChanged, {filter(changeInfo) { expectTypeOf(changeInfo).toEqualTypeOf(); return true; - }); + }}); }); }); diff --git a/source/one-event.ts b/source/one-event.ts index 5f25c0b..1b775c9 100644 --- a/source/one-event.ts +++ b/source/one-event.ts @@ -9,12 +9,20 @@ type EventParameters > = Parameters[0]>; -export async function oneEvent< - Event extends RemovableEvent, ->( +export async function oneEvent>( event: Event, - filter?: (...parameters: EventParameters) => boolean, + { + filter, + signal, + }: { + filter?: (...parameters: EventParameters) => boolean; + signal?: AbortSignal; + } = {}, ): Promise { + if (signal?.aborted) { + return; + } + await new Promise(resolve => { // TODO: VoidFunction should not be necessary, it's equivalent to using "any" const listener: VoidFunction = (...parameters: EventParameters) => { @@ -25,5 +33,11 @@ export async function oneEvent< }; event.addListener(listener); + + // TODO: The abort listener is left behind if never aborted + signal?.addEventListener('abort', () => { + resolve(); + event.removeListener(listener); + }); }); }