{"id":15092867,"url":"https://github.com/luavixen/patella","last_synced_at":"2025-04-12T06:32:56.746Z","repository":{"id":54765619,"uuid":"278025035","full_name":"luavixen/Patella","owner":"luavixen","description":"Patella is a library for reactive programming in JavaScript, inspired by Hyperactiv and Vue.js.","archived":false,"fork":false,"pushed_at":"2021-08-23T00:00:08.000Z","size":467,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-11-07T11:04:55.633Z","etag":null,"topics":["deno","javascript","javascript-library","reactive","reactive-objects","reactive-programming","reactive-properties","reactivity","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/patella","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/luavixen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-07-08T07:48:23.000Z","updated_at":"2023-03-17T11:08:48.000Z","dependencies_parsed_at":"2022-08-14T02:10:32.437Z","dependency_job_id":null,"html_url":"https://github.com/luavixen/Patella","commit_stats":null,"previous_names":["luawtf/luar"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luavixen%2FPatella","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luavixen%2FPatella/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luavixen%2FPatella/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luavixen%2FPatella/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/luavixen","download_url":"https://codeload.github.com/luavixen/Patella/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223502361,"owners_count":17155938,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["deno","javascript","javascript-library","reactive","reactive-objects","reactive-programming","reactive-properties","reactivity","typescript"],"created_at":"2024-09-25T11:01:49.520Z","updated_at":"2024-11-07T11:05:14.553Z","avatar_url":"https://github.com/luavixen.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp\u003e\n  \u003ca href=\"https://www.npmjs.com/package/patella\"\u003e\n    \u003cimg src=\"https://badgen.net/npm/v/patella?style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/patella?activeTab=dependencies\"\u003e\n    \u003cimg src=\"https://badgen.net/bundlephobia/dependency-count/patella?style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/luavixen/Patella/blob/master/lib/patella.d.ts\"\u003e\n    \u003cimg src=\"https://badgen.net/npm/types/patella?style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://bundlephobia.com/result?p=patella\"\u003e\n    \u003cimg src=\"https://badgen.net/bundlephobia/minzip/patella?style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/luavixen/Patella/actions\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/workflow/status/luavixen/Patella/Continuous%20integration%20and%20deployment?style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://coveralls.io/github/luavixen/Patella\"\u003e\n    \u003cimg src=\"https://badgen.net/coveralls/c/github/luavixen/Patella?style=flat-square\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/luavixen/Patella/blob/master/LICENSE\"\u003e\n    \u003cimg src=\"https://badgen.net/github/license/luavixen/Patella?style=flat-square\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n# Patella \u0026#x1F501;\nPatella, formerly known as Luar, is a library for \u003ca href=\"https://wikipedia.org/wiki/Reactive_programming\"\u003ereactive programming\u003c/a\u003e in JavaScript, inspired by [Hyperactiv](https://github.com/elbywan/hyperactiv) and [Vue.js](https://vuejs.org/).\nPatella is compatible with Chrome 5, Firefox 4, and Internet Explorer 9.\n\nThe [patellar tendon is responsible for the well known \"knee-jerk reaction\"](https://wikipedia.org/wiki/Patellar_reflex).\n\nJump to one of:\n  - [Installation](#installation)\n  - [Usage](#usage)\n  - [Examples and snippets](#examples-and-snippets)\n  - [Pitfalls](#pitfalls)\n  - [API](#api)\n  - [Authors](#authors)\n  - [License](#license)\n\n## Installation\nPatella is available via [npm](https://www.npmjs.com/package/patella):\n```sh\n$ npm install patella\n```\n```javascript\n// ECMAScript module environments\nimport { observe, ignore, computed, dispose } from \"patella\";\n// CommonJS environments\nconst { observe, ignore, computed, dispose } = require(\"patella\");\n```\n\nOr, for people working without a bundler, it can be included from [UNPKG](https://www.unpkg.com/browse/patella@latest/):\n```html\n\u003cscript src=\"https://www.unpkg.com/patella\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  Patella.observe({});\n  Patella.ignore({});\n  Patella.computed(() =\u003e {});\n  Patella.dispose(() =\u003e {});\n\u003c/script\u003e\n```\n\nVarious other Patella builds are available in the [dist](./dist) folder, including sourcemaps and minified versions.\nMinification is performed using both [Terser](https://github.com/terser/terser) and [UglifyJS](https://github.com/mishoo/UglifyJS) using custom configurations designed for a balance of speed and size (Patella is a micro-library at 900~ bytes gzipped).\n\n## Usage\nPatella provides functions for observing object mutations and acting on those mutations automatically.\nPossibly the best way to learn is by example, so let's take a page out of [Vue.js's guide](https://vuejs.org/v2/guide/events.html) and make a button that counts how many times it has been clicked using Patella's `observe(object)` and `computed(func)`:\n```html\n\u003ch1\u003eClick Counter\u003c/h1\u003e\n\u003cbutton onclick=\"model.clicks++\"\u003e\u003c/button\u003e\n\u003cscript\u003e\n  const $button = document.getElementsByTagName(\"button\")[0];\n  const model = Patella.observe({\n    clicks: 0\n  });\n  Patella.computed(() =\u003e {\n    $button.innerText = model.clicks\n      ? `I've been clicked ${model.clicks} times`\n      : \"Click me!\";\n  });\n\u003c/script\u003e\n```\n![](./examples/counter-vid.gif)\u003cbr\u003e\nView the [full source](./examples/counter.html) or [try it on JSFiddle](https://jsfiddle.net/luawtf/hL6g4emk/latest).\n\nNotice how in the above example, the `\u003cbutton\u003e` doesn't do any extra magic to change its text when clicked; it just increments the model's click counter, which is \"connected\" to the button's text in the computed function.\n\nNow let's try doing some math, here's a snippet that adds and multiplies two numbers:\n```javascript\nconst calculator = Patella.observe({\n  left:    1,\n  right:   1,\n  sum:     0,\n  product: 0\n});\n\n// Connect left, right -\u003e sum\nPatella.computed(() =\u003e calculator.sum = calculator.left + calculator.right);\n// Connect left, right -\u003e product\nPatella.computed(() =\u003e calculator.product = calculator.left * calculator.right);\n\ncalculator.left = 2;\ncalculator.right = 10;\nconsole.log(calculator.sum, calculator.product); // Output: 12 20\n\ncalcuator.left = 3;\nconsole.log(calculator.sum, calculator.product); // Output: 13 30\n```\nPretty cool, right?\nPatella's main goal is to be as simple as possible; you only need two functions to build almost anything.\n\n## Examples and snippets\nJump to one of:\n  - [Concatenator](#concatenator)\n  - [Debounced search](#debounced-search)\n  - [Pony browser](#pony-browser)\n  - [Multiple objects snippet](#multiple-objects-snippet)\n  - [Linked computed functions snippet](#linked-computed-functions-snippet)\n\n### Concatenator\n```html\n\u003ch1\u003eConcatenator\u003c/h1\u003e\n\u003cinput type=\"text\" oninput=\"model.first = value\" placeholder=\"Enter some\"/\u003e\n\u003cinput type=\"text\" oninput=\"model.second = value\" placeholder=\"text!\"/\u003e\n\u003ch3 id=\"output\"\u003e\u003c/h3\u003e\n\u003cscript\u003e\n  const $output = document.getElementById(\"output\");\n  const model = Patella.observe({\n    first: \"\",\n    second: \"\",\n    full: \"\"\n  });\n  Patella.computed(() =\u003e {\n    model.full = model.first + \" \" + model.second;\n  });\n  Patella.computed(() =\u003e {\n    $output.innerText = model.full;\n  });\n\u003c/script\u003e\n```\n![](./examples/concatenator-vid.gif)\u003cbr\u003e\nView the [full source](./examples/concatenator.html) or [try it on JSFiddle](https://jsfiddle.net/luawtf/zvnm4jp7/latest).\n\n### Debounced search\n```html\n\u003ch1\u003eDebounced Search\u003c/h1\u003e\n\u003cinput type=\"text\" oninput=\"model.input = value\" placeholder=\"Enter your debounced search\"/\u003e\n\u003ch3 id=\"search\"\u003e\u003c/h3\u003e\n\u003cscript\u003e\n  const $search = document.getElementById(\"search\");\n\n  const model = Patella.observe({\n    input: \"\",\n    search: \"\"\n  });\n\n  Patella.computed(() =\u003e {\n    search.innerText = model.search;\n  });\n\n  let timeoutID;\n  Patella.computed(() =\u003e {\n    const input = model.input;\n    if (timeoutID) clearTimeout(timeoutID);\n    timeoutID = setTimeout(() =\u003e {\n      model.search = input;\n    }, 1000);\n  });\n\u003c/script\u003e\n```\n![](./examples/debounce-vid.gif)\u003cbr\u003e\nView the [full source](./examples/debounce.html) or [try it on JSFiddle](https://jsfiddle.net/luawtf/abd3qxft/latest).\n\n### Pony browser\n```html\n\u003cmain id=\"app\"\u003e\n  \u003ch1\u003ePony Browser\u003c/h1\u003e\n  \u003cselect\u003e\u003c/select\u003e\n  \u003cul\u003e\u003c/ul\u003e\n  \u003cinput type=\"text\" placeholder=\"Add another pony\"/\u003e\n\u003c/main\u003e\n\u003cscript\u003e\n  // Find elements\n  const $app = document.getElementById(\"app\");\n  const [, $select, $list, $input] = $app.children;\n\n  // Declare model\n  const model = Patella.observe({\n    /* Truncated, find full source in ./examples/pony.html */\n  });\n\n  // Populate \u003cselect\u003e\n  for (const [value, { name }] of Object.entries(model.characterSets)) {\n    const $option = document.createElement(\"option\");\n    $option.value = value;\n    $option.innerText = name;\n    $select.appendChild($option);\n  }\n\n  // Connect model.selected.key -\u003e model.selected.current\n  Patella.computed(() =\u003e {\n    model.selected.current = model.characterSets[model.selected.key];\n  });\n\n  // Connect model.selected.current.members -\u003e \u003cul\u003e\n  Patella.computed(() =\u003e {\n    $list.innerHTML = \"\";\n    for (const member of model.selected.current.members) {\n      const $entry = document.createElement(\"li\");\n      $entry.innerText = member;\n      $list.appendChild($entry);\n    }\n  });\n\n  // Connect \u003cselect\u003e -\u003e model.selected.key\n  $select.addEventListener(\"change\", () =\u003e {\n    model.selected.key = $select.value;\n  });\n\n  // Connect \u003cinput\u003e -\u003e model.selected.current.members\n  $input.addEventListener(\"keyup\", ({ key }) =\u003e {\n    if (key !== \"Enter\") return;\n\n    const currentSet = model.selected.current;\n    currentSet.members = [\n      ...currentSet.members,\n      $input.value\n    ];\n\n    $input.value = \"\";\n  });\n\u003c/script\u003e\n```\n![](./examples/pony-vid.gif)\u003cbr\u003e\nView the [full source](./examples/pony.html) or [try it on JSFiddle](https://jsfiddle.net/luawtf/84wmaz0g/latest).\n\n## Multiple objects snippet\n```javascript\n// Setting up some reactive objects that contain some data about a US president...\n// Disclaimer: I am not an American :P\nconst person = Patella.observe({\n  name: { first: \"George\", last: \"Washington\" },\n  age: 288\n});\nconst account = Patella.observe({\n  user: \"big-george12\",\n  password: \"IHateTheQueen!1\"\n});\n\n// Declare that we will output a log message whenever person.name.first, account.user, or person.age are updated\nPatella.computed(() =\u003e console.log(\n  `${person.name.first}'s username is ${account.user} (${person.age} years old)`\n)); // Output: George's username is big-george12 (288 years old)\n\n// Changing reactive properties will only run computed functions that depend on them\naccount.password = \"not-telling\"; // Does not output (no computed function depends on this)\n\n// All operators work when updating properties\naccount.user += \"3\"; // Output: George's username is big-george123 (288 years old)\nperson.age++; // Output: George's username is big-george123 (289 years old)\n\n// You can even replace objects entirely\n// This will automatically observe this new object and will still trigger dependant computed functions\n// Note: You should ideally use ignore or dispose to prevent depending on objects that get replaced, see pitfalls\nperson.name = {\n  first: \"Abraham\",\n  last: \"Lincoln\"\n}; // Output: Abraham's username is big-george123 (289 years old)\n\nperson.name.first = \"Thomas\"; // Output: Thomas's username is big-george123 (289 years old)\n```\n\n### Linked computed functions snippet\n```javascript\n// Create our nums object, with some default values for properties that will be computed\nconst nums = Patella.observe({\n  a: 33, b: 23, c: 84,\n  x: 0,\n  sumAB: 0, sumAX: 0, sumCX: 0,\n  sumAllSums: 0\n});\n\n// Declare that (x) will be equal to (a + b + c)\nPatella.computed(() =\u003e nums.x = nums.a + nums.b + nums.c);\n// Declare that (sumAB) will be equal to (a + b)\nPatella.computed(() =\u003e nums.sumAB = nums.a + nums.b);\n// Declare that (sumAX) will be equal to (a + x)\nPatella.computed(() =\u003e nums.sumAX = nums.a + nums.x);\n// Declare that (sumCX) will be equal to (c + x)\nPatella.computed(() =\u003e nums.sumCX = nums.c + nums.x);\n// Declare that (sumAllSums) will be equal to (sumAB + sumAX + sumCX)\nPatella.computed(() =\u003e nums.sumAllSums = nums.sumAB + nums.sumAX + nums.sumCX);\n\n// Now lets check the (sumAllSums) value\nconsole.log(nums.sumAllSums); // Output: 453\n\n// Notice that when we update one value ...\nnums.c += 2;\n// ... all the other values update! (since we declared them as such)\nconsole.log(nums.sumAllSums); // Output: 459\n```\n\n## Pitfalls\nPatella uses JavaScript's [getters](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Functions/get)[ and ](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)[setters](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Functions/set) to make all the reactivity magic possible, which comes with some tradeoffs that other libraries like [Hyperactiv](https://github.com/elbywan/hyperactiv) (which uses [Proxy](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy)) don't have to deal with.\nThis section details some of the stuff to look out for when using Patella in your applications.\n\n### Computed functions can cause infinite loops\n```javascript\nconst object = Patella.observe({ x: 10, y: 20 });\n\nPatella.computed(function one() {\n  if (object.x \u003e 20) object.y++;\n});\n\nPatella.computed(function two() {\n  if (object.y \u003e 20) object.x++;\n});\n\nobject.x = 25;\n// Uncaught Error: Computed queue overflow! Last 10 functions in the queue:\n// 1993: one\n// 1994: two\n// 1995: one\n// 1996: two\n// 1997: one\n// 1998: two\n// 1999: one\n// 2000: two\n// 2001: one\n// 2002: two\n// 2003: one\n```\n\n### Array mutations do not trigger dependencies\n```javascript\nconst object = Patella.observe({\n  array: [1, 2, 3]\n});\n\nPatella.computed(() =\u003e console.log(object.array)); // Output: 1,2,3\n\nobject.array[2] = 4; // No output, arrays are not reactive!\nobject.array.push(5); // Still no output, as Patella does not replace array methods\n\n// If you want to use arrays, do it like this:\n// 1. Run your operations\nobject.array[2] = 3;\nobject.array[3] = 4;\nobject.array.push(5);\n// 2. Then set the array to itself\nobject.array = object.array; // Output: 1,2,3,4,5\n```\n\n### Properties added after observation are not reactive\n```javascript\nconst object = Patella.observe({ x: 10 });\nobject.y = 20;\n\nPatella.computed(() =\u003e console.log(object.x)); // Output: 10\nPatella.computed(() =\u003e console.log(object.y)); // Output: 20\n\nobject.x += 2; // Output: 12\n\nobject.y += 2; // No output, as this property was added after observation\n\nPatella.observe(object);\n\nobject.y += 2; // Still no output, as objects cannot be re-observed\n```\n\n### Prototypes will not be made reactive unless explicitly observed\n```javascript\nconst object = { a: 20 };\nconst prototype = { b: 10 };\nObject.setPrototypeOf(object, prototype);\n\nPatella.observe(object);\n\nPatella.computed(() =\u003e console.log(object.a)); // Output: 10\nPatella.computed(() =\u003e console.log(object.b)); // Output: 20\n\nobject.a = 15; // Output: 15\n\nobject.b = 30; // No output, as this isn't an actual property on the object\nprototype.b = 36; // No output, as prototypes are not made reactive by observe\n\nPatella.observe(prototype);\n\nprototype.b = 32; // Output: 32\n```\n\n### Non-enumerable and non-configurable properties will not be made reactive\n```javascript\nconst object = { x: 1 };\nObject.defineProperty(object, \"y\", {\n  configurable: true,\n  enumerable: false,\n  value: 2\n});\nObject.defineProperty(object, \"z\", {\n  configurable: false,\n  enumerable: true,\n  value: 3\n});\n\nPatella.observe(object);\n\nPatella.computed(() =\u003e console.log(object.x)); // Output: 1\nPatella.computed(() =\u003e console.log(object.y)); // Output: 2\nPatella.computed(() =\u003e console.log(object.z)); // Output: 3\n\nobject.x--; // Output: 0\n\nobject.y--; // No output as this property is non-enumerable\nobject.z--; // No output as this property is non-configurable\n```\n\n### Enumerable and configurable but non-writable properties will be made writable\n```javascript\nconst object = {};\nObject.defineProperty(object, \"val\", {\n  configurable: true,\n  enumerable: true,\n  writable: false,\n  value: 10\n});\n\nobject.val = 20; // Does nothing\nconsole.log(object.val); // Output: 10\n\nPatella.observe(object);\n\nobject.val = 20; // Works because the property descriptor has been overwritten\nconsole.log(object.val); // Output: 20\n```\n\n### Getter/setter properties will be accessed then lose their getter/setters\n```javascript\nconst object = {\n  get val() {\n    console.log(\"Gotten!\");\n    return 10;\n  }\n};\n\nobject.val; // Output: Gotten!\n\nPatella.observe(object); // Output: Gotten!\n\nobject.val; // No output as the getter has been overwritten\n```\n\n### Properties named `__proto__` are ignored\n```javascript\nconst object = {};\nObject.defineProperty(object, \"__proto__\", {\n  configurable: true,\n  enumerable: true,\n  writable: true,\n  value: 10\n});\n\nPatella.observe(object);\n\nPatella.computed(() =\u003e console.log(object.__proto__)); // Output: 10\n\nobject.__proto__++; // No output as properties named __proto__ are ignored\n```\n\n## API\n\u003ch4 id=\"observe\"\u003e\u003ccode\u003efunction observe(object)\u003c/code\u003e\u003c/h4\u003e\nDescription:\n\u003cul\u003e\n  \u003cli\u003e\n    Makes an object and its properties reactive recursively.\n    Subobjects (but not subfunctions!) will also be observed.\n    Note that \u003ccode\u003eobserve\u003c/code\u003e does not create a new object, it mutates the object passed into it: \u003ccode\u003eobserve(object) === object\u003c/code\u003e.\n  \u003c/li\u003e\n\u003c/ul\u003e\nParameters:\n\u003cul\u003e\n  \u003cli\u003e\u003ccode\u003eobject\u003c/code\u003e \u0026mdash; Object or function to make reactive\u003c/li\u003e\n\u003c/ul\u003e\nReturns:\n\u003cul\u003e\n  \u003cli\u003eInput \u003ccode\u003eobject\u003c/code\u003e, now reactive\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch4 id=\"ignore\"\u003e\u003ccode\u003efunction ignore(object)\u003c/code\u003e\u003c/h4\u003e\nDescription:\n\u003cul\u003e\n  \u003cli\u003e\n    Prevents an object from being made reactive, \u003ccode\u003eobserve\u003c/code\u003e will do nothing.\n    Note that \u003ccode\u003eignore\u003c/code\u003e is not recursive, so subobjects can still be made reactive by calling \u003ccode\u003eobserve\u003c/code\u003e on them directly.\n  \u003c/li\u003e\n\u003c/ul\u003e\nParameters:\n\u003cul\u003e\n  \u003cli\u003e\u003ccode\u003eobject\u003c/code\u003e \u0026mdash; Object or function to ignore\u003c/li\u003e\n\u003c/ul\u003e\nReturns:\n\u003cul\u003e\n  \u003cli\u003eInput \u003ccode\u003eobject\u003c/code\u003e, now permanently ignored\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch4 id=\"computed\"\u003e\u003ccode\u003efunction computed(func)\u003c/code\u003e\u003c/h4\u003e\nDescription:\n\u003cul\u003e\n  \u003cli\u003e\n    Calls \u003ccode\u003efunc\u003c/code\u003e with no arguments and records a list of all the reactive properties it accesses.\n    \u003ccode\u003efunc\u003c/code\u003e will then be called again whenever any of the accessed properties are mutated.\n    Note that if \u003ccode\u003efunc\u003c/code\u003e has been \u003ccode\u003edispose\u003c/code\u003ed with \u003ccode\u003e!!clean === false\u003c/code\u003e, no operation will be performed.\n  \u003c/li\u003e\n\u003c/ul\u003e\nParameters:\n\u003cul\u003e\n  \u003cli\u003e\u003ccode\u003efunc\u003c/code\u003e \u0026mdash; Function to execute\u003c/li\u003e\n\u003c/ul\u003e\nReturns:\n\u003cul\u003e\n  \u003cli\u003eInput \u003ccode\u003efunc\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch4 id=\"dispose\"\u003e\u003ccode\u003efunction dispose(func, clean)\u003c/code\u003e\u003c/h4\u003e\nDescription:\n\u003cul\u003e\n  \u003cli\u003e\n    \"Disposes\" a function that was run with \u003ccode\u003ecomputed\u003c/code\u003e, deregistering it so that it will no longer be called whenever any of its accessed reactive properties update.\n    The \u003ccode\u003eclean\u003c/code\u003e parameter controls whether calling \u003ccode\u003ecomputed\u003c/code\u003e with \u003ccode\u003efunc\u003c/code\u003e will work or no-op.\n  \u003c/li\u003e\n\u003c/ul\u003e\nParameters:\n\u003cul\u003e\n  \u003cli\u003e\u003ccode\u003efunc\u003c/code\u003e \u0026mdash; Function to dispose, omit to dispose the currently executing computed function\u003c/li\u003e\n  \u003cli\u003e\u003ccode\u003eclean\u003c/code\u003e \u0026mdash; If truthy, only deregister the function from all dependencies, but allow it to be used with \u003ccode\u003ecomputed\u003c/code\u003e again in the future\u003c/li\u003e\n\u003c/ul\u003e\nReturns:\n\u003cul\u003e\n  \u003cli\u003eInput \u003ccode\u003efunc\u003c/code\u003e if \u003ccode\u003efunc\u003c/code\u003e is valid, otherwise \u003ccode\u003eundefined\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\n## Authors\nMade with ❤ by Lua MacDougall ([foxgirl.dev](https://foxgirl.dev/))\n\n## License\nThis project is licensed under [MIT](LICENSE).\nMore info in the [LICENSE](LICENSE) file.\n\n\u003ci\u003e\"A short, permissive software license. Basically, you can do whatever you want as long as you include the original copyright and license notice in any copy of the software/source. There are many variations of this license in use.\"\u003c/i\u003e - [tl;drLegal](https://tldrlegal.com/license/mit-license)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluavixen%2Fpatella","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fluavixen%2Fpatella","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluavixen%2Fpatella/lists"}