send-and-receive
Version:
Two small helper methods that simplify communication between nodes in different subtrees of the browser DOM.
159 lines (158 loc) • 4.87 kB
TypeScript
interface Context {
received: number;
remaining: number;
cancelled: boolean;
cancel: () => void;
paused: boolean;
pause: () => void;
resume: () => void;
}
export declare type Subscription = Readonly<Context>;
/**
* Dispatches an event of the specified `type` with the
* specified `data` (optional).
*
* @param type The name of the event.
* @param data The optional payload of the event.
* @example
*
* send('player:play', { src: 'song.mp3' });
*/
export declare function send(type: string, data?: any): boolean;
declare type Callback<T> = (data: T) => void;
interface ReceiveOptions {
readonly limit: number;
}
/**
* Listens on dispatched events of the specified `type`
* and, when it receives one, invokes `callback` with the
* data passed when sending.
*
* @param type The name of the event.
* @param callback The function to invoke.
* @param options The configuration options.
* @returns A subscription object.
* @example
*
* const subscription = receive('player:play', (data) => {
* doSomethingWith(data);
* });
*
* @description
*
* Use the returned subscription object to retrieve some
* metadata or to cancel receiving further events:
*
* @example
*
* subscription.received //=> How often has the event been received?
* subscription.remaining //=> How many remaining events can it receive?
*
* subscription.cancelled //=> Did we completely opt out of receiving further events?
* subscription.cancel() //=> Unlisten from the event and set cancelled status.
*
* subscription.paused //=> Did we temporarily stop receiving further events?
* subscription.pause() //=> Pause listening and set paused status.
* subscription.resume() //=> Resume listening and unset paused status.
*
* @description
*
* Note that both `subscription.pause()` and `subscription.resume()`
* will throw an error if the subscription has been cancelled.
*
* By default, the number of events it can receive is not limited, which
* means `subscription.remaining` will always return *positive infinity*.
*
* Besides calling `subscription.cancel()` in order to stop listening to
* further events, you can also restrict the number of times the event
* will be received by supplying the `limit` option:
*
* @example
*
* receive('player:play', callback, { limit: 1 });
*
* @description
*
* Here, after the event has been received once, it will be auto-cancelled.
* Furthermore, the subscription's `received` property will have changed
* from `0` to `1`, and the `remaining` property from `1` to `0`.
*/
export declare function receive<T>(type: string, callback: Callback<T>, { limit }?: ReceiveOptions): Subscription;
/**
* A convenience method for the case when you want to receive
* the event only once.
*
* @param type The name of the event.
* @param callback The function to invoke.
* @returns A subscription object.
* @example
*
* receiveOnce('player:play', callback);
*
* @description
*
* This is semantically the same as calling `receive` with
* `{ limit: 1 }` as options.
*/
export declare function receiveOnce<T>(type: string, callback: Callback<T>): Subscription;
declare type CreateResult<T, A extends any[] = [T]> = readonly [(...args: A) => ReturnType<typeof send>, (callback: Callback<T>, options?: ReceiveOptions) => ReturnType<typeof receive>];
/**
* A convenience method to create both a sender function and
* a receiver function for the specified `type`.
*
* @param type The name of the event.
* @returns An array of size 2, where the first element is the
* send function and the second element the receive function.
*
* @description
*
* This method is especially useful when coding in TypeScript,
* as it allows strict-typing the `data`:
*
* @example
*
* // a.ts
* import { create } from 'send-and-receive';
*
* const [sendPlay, receivePlay] = create<Song>('player:play');
*
* export { receivePlay };
*
* // later on (button click, etc.)
* sendPlay({ src: 'song.mp3' });
*
* // b.ts
* import { receivePlay } from './a.js';
*
* receivePlay((song) => {
* doSomethingWith(song.src);
* });
*
* @description
*
* Optionally, you can pass a function as the second argument which
* transforms the arguments passed to `send` into the data structure
* supplied to the `receive` callback:
*
* @example
*
* interface Options {
* action: "push" | "replace";
* }
*
* const [navigateTo, receiveNavigateTo] = create(
* "navigate-to",
* (url: string, options: Options = { action: "push" }) => ({
* ...options,
* url,
* })
* );
*
* // send...
* navigateTo("/foo", { action: "replace" });
*
* // receive...
* receiveNavigateTo(({ url, action }) => history[action](url));
*/
export declare function create<T, A extends any[] = [T]>(type: string, buildData?: (...args: A) => T): CreateResult<T, A>;
export {};