Skip to content

πŸš… Modern event listener for efficient applications based on the subscribe-publish pattern.

License

Notifications You must be signed in to change notification settings

thednp/event-listener

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

98 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

EventListener

Coverage Status ci NPM Version NPM Downloads jsDeliver typescript version vitest version vite version

A TypeScript sourced event listener for efficient applications based on the subscribe-publish pattern, around 700 bytes when minified and packs a surprising amount of power.

Features

  • EventListener is TypeScript sourced, with some types addapted from React;
  • EventListener makes use of the native Map to subscribe/register or unsubscribe/remove listeners, which is perfect since we need to make sure the exact listeners are added/removed; this completely invalidates the need to deconstruct function objects for comparison's sake to make sure event listeners are properly handled;
  • EventListener allows you to register multiple listeners for the same target, even of the same type, but always uses a single globalListener to call them all at once when event is triggered;
  • EventListener "should" be able to manage event options, especially once, meaning that when the option is true, the listener is automatically un-subscribed and detached from target;
  • EventListener will unsubscribe and detach listeners with the same options used when attached, which means you can "lazy" remove listeners on the fly.

Install

pnpm install -D @thednp/event-listener
yarn add -D @thednp/event-listener
npm install -D @thednp/event-listener
deno install -D npm:@thednp/event-listener@latest

CDN

<script src="https://cdn.jsdelivr.net/npm/@thednp/event-listener/dist/event-listener.js"></script>

Use

import * as Listener from '@thednp/event-listener';

// execute a listener once
Listener.on(document, 'DOMContentLoaded', () => {
    console.log('document is now loaded');
  },
  { once: true },
);

// add a listener with `useCapture: false`
function handleMyClick(e: Listener.NativeEvent) {
  if (e.target.tagName === 'button') {
    e.preventDefault();
    e.stopImmediatePropagation();
  }
  console.log('do something else instead');
}
Listener.on(document, 'click', handleMyClick, false);

// remove a listener, `EventListener` will get listener options from registry
Listener.off(document, 'click', handleMyClick);

// add listener to `window`, this listener has no name and cannot be removed
Listener.on(window, 'scroll', () => console.log(window.scrollY));

Since we're implementing Map, you can make use of its prototype to access registry:

// get element listener registry
const documentClickListeners = Listener.registry['click'].get(document);

// returns
Map(1) {
  Entries => [
    0: {
      key: handleMyClick() // listener
      value: false // listener options
    }
  ],
  size: 1, // size of the Map
  prototype: [Prototype(Map)]
}

// check if element has listener
if (documentClickListeners && documentClickListeners.has(handleMyClick)) {
  // do something about it
}

// check if a listener is the one you're looking for
if (documentClickListeners) {
  const [eventListener] = documentClickListeners;
  if (eventListener === handleMyClick) {
    // do something about it
  }
}

// get listener options
const myListenerOptions = documentClickListeners && documentClickListeners.get(handleMyClick);

// returns false, which is the `useCapture` option value added for `handleMyClick`

Advanced Use

You can also make use of the types for more consistent code:

import { on, FocusEventHandler } from '@thednp/event-listener';

const handleMyFocus: FocusEventHandler<HTMLInputElement> = (e) => {
  console.log(e)
}

const myInput = document.querySelector('input') || document.createElement('input');
on(myInput, 'focus', handleMyFocus);

For more advanced use, check out the demo, showcasing the EventListener usage with a demo component.

Run the tests suite

  • Download the package from Github;
  • unpack/unzip and open the folder with your editor;
  • open your terminal and navigate to the root of the unpacked folder;
  • run npm install or npm update, takes a few minutes to download the Electron browser;
  • run npm run test-ui to open the browser mode testing OR npm run test to run the tests in headless mode.

License

EventListener is released under the MIT License.