{"bugs":{"url":"https://github.com/alexreardon/bind-event-listener/issues"},"dist":{"shasum":"9d7d7a907a1d7a05d15b2fd620a780b7bd06d34a","tarball":"https://registry.npmjs.org/bind-event-listener/-/bind-event-listener-3.0.0-beta.1.tgz","fileCount":15,"integrity":"sha512-MaGzCng1RnlOzNwq3Rr/9/Ab1gRodPV6by46M53/FOZ5ambuDH4Qs8KcJH1OQ6rUYcMxUgz5Oc4pyIwDbMEW2A==","signatures":[{"sig":"MEUCIQCwh+b6TH4vRBJZDtXMXJ1J6siYScrP4DpgYyVnAgEyCwIgY6BZcK0Ub4bOw+yShexdZxXMQGfof15gXZMou+TYBBE=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":19753,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJkSL99ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmoccg//TxoWylzTmAAuMOZUcm9euBQkjW/DaGI6qIvH9uepjVUZhRc+\r\nkS3OkWpZ2EtEu/jwKSYertQMbrLY8uxTncav/pvUaPEPDY6JCB+ae/lo8hY0\r\neCoNcAHDGb1We1jigFvGoI/07xVwZmePAg1Y04CfauGdQx+kAQnt+8vtiOOi\r\nOPmwH1Lvvao4BX7GKS133ZLyCCZALSvy3k5KGd84ic31N4Q3fIM6J42YCloC\r\nrwc1mRGQD2aFEm1ffbq5CUJrB/3aLasSXpC093QlrMa6TYLrAfxKt0az6UnU\r\nG5PHIzQnGqr4xqS0ceMtvg7FdKCYrYZErjVysgZsF8Y/qJM6Z7dQurnDQ+YO\r\nNw0Df/0Nq4Lt3lWu3iijvBtsPh0OZ60Yi/2K+5DT6j174t/UASQCXacufZ1u\r\n2ew2wb/l6PF9SmMwYOav2XOZRNklRQPiLIuvp3g9P0nAOnT1w9kaVyrd7EI9\r\nZz/PyydZ9VKxZQX+0x/0MTVyxqt0Hx7ZgEbrbIdDTASht4nExMyiz0HTW7UH\r\nDJOimaF9dlL9uArPkQ5zempZFrpPtQVH50OMsP+DkmSKPPtTCCY0mWaH51MO\r\nkku+ZgvlbDRJ0Y/vOn1kf8PYGCaONMa/q5sdrBIrq9P2cHkQPM1Fxw1/kKAA\r\nJKsQ37Krwdxvlk2UDf+G7HsofCPmAwnD2d0=\r\n=GJsF\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","name":"bind-event-listener","types":"dist/index.d.ts","author":{"name":"Alex Reardon","email":"alexreardon@gmail.com"},"config":{"prettier_target":"src/**/*.{ts,js,jsx,md,json} test/**/*.{ts,js,jsx,md,json}"},"readme":"# bind-event-listener\n\n[![npm](https://img.shields.io/npm/v/bind-event-listener.svg)](https://www.npmjs.com/package/bind-event-listener)\n![types](https://img.shields.io/badge/types-typescript-blueviolet)\n[![minzip](https://img.shields.io/bundlephobia/minzip/bind-event-listener.svg)](https://www.npmjs.com/package/bind-event-listener)\n\n> A utility to make binding and (**especially**) unbinding DOM events easier.\n> I seem to write this again with every new project, so I made it a library\n\n```ts\nimport { bind, UnbindFn } from 'bind-event-listener';\n\nconst unbind: UnbindFn = bind(button, {\n  type: 'click',\n  listener: function onClick(event) {},\n});\n\n// when you are all done:\nunbind();\n```\n\n```ts\nimport { bindAll } from 'bind-event-listener';\n\nconst unbind = bindAll(button, [\n  {\n    type: 'click',\n    listener: function onClick(event) {},\n    options: { capture: true },\n  },\n  {\n    type: 'mouseover',\n    listener: function onMouseOver(event) {},\n  },\n]);\n\n// when you are all done:\nunbind();\n```\n\n## Rationale\n\nWhen using `addEventListener()`, **correctly unbinding** events with `removeEventListener()` can be tricky.\n\n1. You need to remember to call `removeEventListener` (it can be easy to forget!)\n\n<details>\n<summary>Example</summary>\n\n```ts\ntarget.addEventListener('click', onClick, options);\n\ntarget.removeEventListener('click', onClick, options);\n```\n\n</details>\n\n2. You need to pass in the same listener _reference_ to `removeEventListener`\n\n<details>\n<summary>Example</summary>\n\n```ts\ntarget.addEventListener(\n  'click',\n  function onClick() {\n    console.log('clicked');\n  },\n  options,\n);\n\n// Even those the functions look the same, they don't have the same reference.\n// The original onClick is not unbound!\ntarget.removeEventListener(\n  'click',\n  function onClick() {\n    console.log('clicked');\n  },\n  options,\n);\n```\n\n```ts\n// Inline arrow functions can never be unbound because you have lost the reference!\ntarget.addEventListener('click', () => console.log('i will never unbind'), options);\ntarget.removeEventListener('click', () => console.log('i will never unbind'), options);\n```\n\n</details>\n\n3. You need to pass in the same `capture` value option\n\n<details>\n<summary>Example</summary>\n\n```ts\n// add a listener: AddEventListenerOptions format\ntarget.addEventListener('click', onClick, { capture: true });\n\n// not unbound: no capture value\ntarget.removeEventListener('click', onClick);\n\n// not unbound: different capture value\ntarget.removeEventListener('click', onClick, { capture: false });\n\n// successfully unbound: same capture value\ntarget.removeEventListener('click', onClick, { capture: true });\n// this would also unbind (different notation)\ntarget.removeEventListener('click', onClick, true /* shorthand for { capture: true } */);\n```\n\n```ts\n// add a listener: boolean capture format\ntarget.addEventListener('click', onClick, true /* shorthand for { capture: true } */);\n\n// not unbound: no capture value\ntarget.addEventListener('click', onClick);\n// not unbound: different capture value\ntarget.addEventListener('click', onClick, false);\n\n// successfully unbound: same capture value\ntarget.addEventListener('click', onClick, true);\n// this would also unbind (different notation)\ntarget.addEventListener('click', onClick, { capture: true });\n```\n\n</details>\n\n**`bind-event-listener` solves these problems**\n\n1. When you bind an event (or events with `bindAll`) you get back a simple `unbind` function\n2. The unbind function ensures the same listener _reference_ is passed to `removeEventListener`\n3. The unbind function ensures that whatever `capture` value is used with `addEventListener` is used with `removeEventListener`\n\nYou will find an even fuller rationale for this project in my course: [\"The Ultimate Guide for Understanding DOM Events\"](https://egghead.io/courses/the-ultimate-guide-for-understanding-dom-events-6c0c0d23?af=2jc3e4)\n\n[![share-card-dom-events](https://user-images.githubusercontent.com/2182637/120963089-52a45f00-c7a4-11eb-82a7-a04c2731999a.jpg)](https://egghead.io/courses/the-ultimate-guide-for-understanding-dom-events-6c0c0d23?af=2jc3e4)\n\n## Usage\n\n### `bind`: basic\n\n```ts\nimport { bind, UnbindFn } from 'bind-event-listener';\n\nconst unbind: UnbindFn = bind(button, {\n  type: 'click',\n  listener: onClick,\n});\n\n// when your are all done:\nunbind();\n```\n\n### `bind`: with options\n\n```ts\nimport { bind } from 'bind-event-listener';\n\nconst unbind = bind(button, {\n  type: 'click',\n  listener: onClick,\n  options: { capture: true, passive: false },\n});\n\n// when you are all done:\nunbind();\n```\n\n### `bindAll`: basic\n\n```ts\nimport { bindAll } from 'bind-event-listener';\n\nconst unbind = bindAll(button, [\n  {\n    type: 'click',\n    listener: onClick,\n  },\n]);\n\n// when you are all done:\nunbind();\n```\n\n### `bindAll`: with options\n\n```ts\nimport { bindAll } from 'bind-event-listener';\n\nconst unbind = bindAll(button, [\n  {\n    type: 'click',\n    listener: onClick,\n    options: { passive: true },\n  },\n  // default options that are applied to all bindings\n  { capture: false },\n]);\n\n// when you are all done:\nunbind();\n```\n\nWhen using `defaultOptions` for `bindAll`, the `defaultOptions` are merged with the `options` on each binding. Options on the individual bindings will take precedent. You can think of it like this:\n\n```ts\nconst merged: AddEventListenerOptions = {\n  ...defaultOptions,\n  ...options,\n};\n```\n\n> Note: it is a little bit more complicated than just object spreading as the library will also behave correctly when passing in a `boolean` capture argument. An options value can be a boolean `{ options: true }` which is shorthand for `{ options: {capture: true } }`\n\n## Types\n\nThanks to the great work by [@Ayub-Begimkulov](https://github.com/Ayub-Begimkulov) `bind-event-listener` has fantastic TypeScript types\n\n> ⚠️ TypeScript 4.1+ is required\n\n```ts\nimport invariant from 'tiny-invariant';\nimport { bind } from 'bind-event-listener';\n\nbind(window, {\n  type: 'click',\n  function: function onClick(event) {\n    // `event` is correctly typed as a 'MouseEvent'\n    // `this` is correctly typed as `window` (the event target that the event listener is added to)\n  },\n});\n\nconst button = document.querySelector('button');\ninvariant(button instanceof HTMLElement);\n\nbind(button, {\n  type: 'click',\n  function: function onClick(event) {\n    // `event` is correctly typed as a 'MouseEvent'\n    // `this` is correctly typed as `button` (the event target that the event listener is added to)\n  },\n});\n\nconst object = {\n  handleEvent: function onClick(event) {\n    // `event` is correctly typed as a 'MouseEvent'\n    // `this` is correctly typed as `object` (the event listener object that the event listener is added to)\n  },\n};\n\nbind(button, {\n  type: 'click',\n  function: object,\n});\n```\n\n## Recipe: [`react`](https://reactjs.org/) effect\n\nYou can return a [cleanup function](https://reactjs.org/docs/hooks-reference.html#cleaning-up-an-effect) from [`useEffect`](https://reactjs.org/docs/hooks-reference.html#useeffect) (or [`useLayoutEffect`](https://reactjs.org/docs/hooks-reference.html#uselayouteffect)). `bind-event-listener` makes this super convenient because you can just return the unbind function from your effect.\n\n```ts\nimport React, { useState, useEffect } from 'react';\nimport { bind } from 'bind-event-listener';\n\nexport default function App() {\n  const [clickCount, onClick] = useState(0);\n\n  useEffect(() => {\n    const unbind = bind(window, {\n      type: 'click',\n      listener: () => onClick((value) => value + 1),\n    });\n\n    return unbind;\n  }, []);\n\n  return <div>Window clicks: {clickCount}</div>;\n}\n```\n\n> You can play with this [example on codesandbox](https://codesandbox.io/s/bind-event-listener-useeffect-mnfi3)\n\n## Types\n\n```ts\nfunction bind(target: EventTarget, binding: Binding): UnbindFn;\n\nfunction bindAll(\n  target: EventTarget,\n  bindings: Binding[],\n  // AddEventListenerOptions is a built in TypeScript type\n  sharedOptions?: boolean | AddEventListenerOptions,\n): UnbindFn;\n\ntype Binding = {\n  type: string;\n  // EventListenerOrEventListenerObject is a built in TypeScript type\n  listener: EventListenerOrEventListenerObject;\n  options?: boolean | AddEventListenerOptions;\n};\n\ntype UnbindFn = () => void;\n```\n\n> Typescript built in DOM types: [raw view](https://raw.githubusercontent.com/microsoft/TypeScript/master/lib/lib.dom.d.ts), [pretty view](https://github.com/microsoft/TypeScript/blob/master/lib/lib.dom.d.ts) (warning: pretty view seems to crash Github!)\n\n## Cheers 👋\n\nBrought to you by [@alexandereardon](https://twitter.com/alexandereardon)\n","gitHead":"6e8b16f511722623a6fc8102af23b5a32ed1f52a","license":"MIT","private":false,"scripts":{"test":"yarn jest","build":"yarn build:clean && yarn typescript:build","validate":"yarn typescript:check && yarn prettier:check","size:check":"size-limit","build:clean":"rimraf dist","prepublishOnly":"yarn build","prettier:check":"prettier --debug-check $npm_package_config_prettier_target","prettier:write":"prettier --write $npm_package_config_prettier_target","typescript:build":"tsc","typescript:check":"tsc --noEmit && tsc --noEmit --project ./test/tsconfig.json","typescript:watch":"tsc --watch"},"_npmUser":{"name":"alexreardon","email":"alexreardon@gmail.com"},"homepage":"https://github.com/alexreardon/bind-event-listener#readme","keywords":["dom","ui","event listener","event handler"],"repository":{"url":"git+https://github.com/alexreardon/bind-event-listener.git","type":"git"},"size-limit":[{"path":"dist/index.js","limit":"549B"}],"_npmVersion":"8.19.3","description":"Making binding and unbinding DOM events easier","directories":{},"maintainers":[{"name":"alexreardon","email":"alexreardon@gmail.com"}],"sideEffects":false,"_nodeVersion":"18.13.0","dependencies":{},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^29.5.0","rimraf":"^5.0.0","ts-jest":"^29.1.0","prettier":"^2.8.8","ts-expect":"^1.3.0","size-limit":"^8.2.4","typescript":"^5.0.4","@types/jest":"^29.5.1","@types/node":"^18.16.0","expect-type":"^0.15.0","jest-environment-jsdom":"^29.5.0","@size-limit/preset-small-lib":"^8.2.4"},"_npmOperationalInternal":{"tmp":"tmp/bind-event-listener_3.0.0-beta.1_1682489213327_0.6365153111843558","host":"s3://npm-registry-packages"},"_id":"bind-event-listener@3.0.0-beta.1","version":"3.0.0-beta.1"}