{"bugs":{"url":"https://github.com/alexreardon/bind-event-listener/issues"},"dist":{"shasum":"41ba41605712d632aaa7fc6ffff7332e012705cf","tarball":"https://registry.npmjs.org/bind-event-listener/-/bind-event-listener-2.1.0-beta.0.tgz","fileCount":15,"integrity":"sha512-OoF8yQZtszk/fgp7c5qPFK0ftTb5EzVUlW6yVvPFvatL9vIleqhNHl3Hdp1/AgHjicGGf4Y4pI/CCGxGxGLdIg==","signatures":[{"sig":"MEYCIQCiQN3YlG1a1vx/vp7uIIKzWCscSvzb4lxb1TlBc7e7mgIhAO5+EkFOWEdoccegnaZIf7iWiHMIgz7d3S7L2YGI0MPV","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":22027,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJichBOACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrpFw/+IzAtJox2hmxJvIg7+syNfpmVSfGaxwfa6D4DNN6hat55/viB\r\n8m6LrPY8AhzCXl8tmL6EC68GOcQxX8P77h6AfulPA6u/Glr3Q8PqiyHO8n1X\r\nLSyrwo9SwDjkp5zsBTV4NYDcaVVbJAUg42PM6u0ZLTBPadRYth7kCnvFvLfE\r\nKtq1bddcsIl+fphpm40BNMJd6qULbt91bpZiAPbx2w4fMNuLoiZjP6qQ1AM5\r\nK7tB4rgraz+nMWwIto5vzuAUYMWvhMzlxZI9t0Rud5DmiC8w4CMrv7wasKGE\r\n0yrxYbvU9oKU7KY/bqd+a4oEDdu2vXs6jTubEVQSmb5YzjySCVKC3eauNDsa\r\nVoC+jQgI78S8YGy1HiqZM1Hunqde38X38o0NZkGuBk/s4nx/chIcUNch77xJ\r\nMIMIRtsYA1TgHloaYXeTPyt2YTjo8TuF/6kUpqEnTryrjzvNdNgbxMmorh6H\r\n9kPLATCM9tMGrUb4MTqWyLgDIQnUZ0ZjdYYnkyZLqMjcY1QYgztsANBdG1PO\r\naV19vODwM9IkrY6SPW8XFau1QnuqPUdeSPLMqhQHbPA3OdX/ZFN4U5ZXiUdZ\r\nsdYAc8306dYdL8w2IsxU/c14ob918ld28XkVr31E8k9EcvGGaar7wjxuA1uk\r\nelRCbTUEbq1h12Cx0NxuaPGAJfUxcs9TDDg=\r\n=+7rO\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":"37aec31ae72862629c7391697a3a27d050b3959b","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":"yarn tsc --noEmit","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.5.5","description":"Making binding and unbinding DOM events easier","directories":{},"maintainers":[{"name":"alexreardon","email":"alexreardon@gmail.com"}],"sideEffects":false,"_nodeVersion":"16.15.0","dependencies":{},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"jest":"^27.4.7","rimraf":"^3.0.2","ts-jest":"^27.1.3","prettier":"^2.5.1","ts-expect":"^1.3.0","size-limit":"^7.0.5","typescript":"^4.6.4","@types/jest":"^27.4.0","expect-type":"^0.13.0","@size-limit/preset-small-lib":"^7.0.5"},"_npmOperationalInternal":{"tmp":"tmp/bind-event-listener_2.1.0-beta.0_1651642445856_0.9269916563115166","host":"s3://npm-registry-packages"},"_id":"bind-event-listener@2.1.0-beta.0","version":"2.1.0-beta.0"}