{"id":13961762,"url":"https://github.com/capsidjs/capsid","last_synced_at":"2026-01-11T13:30:49.598Z","repository":{"id":30774211,"uuid":"34330984","full_name":"capsidjs/capsid","owner":"capsidjs","description":":pill: Declarative DOM programming library. Lightweight (1.79 kb). See also https://github.com/kt3k/cell, which is the successor project","archived":false,"fork":false,"pushed_at":"2023-02-14T11:55:37.000Z","size":10560,"stargazers_count":90,"open_issues_count":3,"forks_count":7,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-11-11T13:18:29.762Z","etag":null,"topics":["browser","decorators","dom","event-handlers","frontend","javascript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/capsidjs.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,"governance":null}},"created_at":"2015-04-21T14:11:46.000Z","updated_at":"2025-08-27T12:07:13.000Z","dependencies_parsed_at":"2023-07-13T14:42:43.765Z","dependency_job_id":null,"html_url":"https://github.com/capsidjs/capsid","commit_stats":{"total_commits":1129,"total_committers":9,"mean_commits":"125.44444444444444","dds":"0.10983170947741361","last_synced_commit":"9f70403e5f73682f63a6fbb5b27f2d0a10f7c47d"},"previous_names":["kt3k/classcaps","kt3k/class-component","kt3k/custom-class","kt3k/classclamp"],"tags_count":133,"template":false,"template_full_name":null,"purl":"pkg:github/capsidjs/capsid","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capsidjs%2Fcapsid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capsidjs%2Fcapsid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capsidjs%2Fcapsid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capsidjs%2Fcapsid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/capsidjs","download_url":"https://codeload.github.com/capsidjs/capsid/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capsidjs%2Fcapsid/sbom","scorecard":{"id":265288,"data":{"date":"2025-08-11","repo":{"name":"github.com/capsidjs/capsid","commit":"9f70403e5f73682f63a6fbb5b27f2d0a10f7c47d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.4,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 1/28 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:7: update your workflow using https://app.stepsecurity.io/secureworkflow/capsidjs/capsid/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:8: update your workflow using https://app.stepsecurity.io/secureworkflow/capsidjs/capsid/ci.yml/main?enable=pin","Info:   0 out of   1 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 7 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T11:52:20.632Z","repository_id":30774211,"created_at":"2025-08-17T11:52:20.633Z","updated_at":"2025-08-17T11:52:20.633Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27675324,"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","status":"online","status_checked_at":"2025-12-12T02:00:06.775Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["browser","decorators","dom","event-handlers","frontend","javascript"],"created_at":"2024-08-08T17:01:25.389Z","updated_at":"2025-12-12T03:12:31.288Z","avatar_url":"https://github.com/capsidjs.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003cimg src=\"http://capsidjs.github.io/capsid/asset/capsid.svg\" /\u003e\n\n[![ci](https://github.com/capsidjs/capsid/actions/workflows/ci.yml/badge.svg)](https://github.com/capsidjs/capsid/actions/workflows/ci.yml)\n[![deno.land/x](https://shields.io/badge/deno.land/x-v1.8.2-green?logo=deno\u0026style=flat)](https://deno.land/x/capsid)\n[![npm](https://img.shields.io/npm/v/capsid.svg)](https://npm.im/capsid)\n\n- **Declarative DOM programming library** based on **TypeScript decorators**\n- :leaves: **Small.** **1.79 kb.** **No dependencies.**\n- :sunny: **No special syntax.** Capsid uses **standard** HTML and TypeScript,\n  and it **doesn't** use any **non-standard** syntax like JSX, Vue template,\n  etc.\n- :bulb: **Simple.** No virtual DOMs. Capsid encourages the traditional event\n  driven programming in a new style.\n\n# :butterfly: [Mirroring Example][Mirroring Example]\n\nThis example illustrates the basic ideas of `capsid`.\n\n```ts\nimport { component, on, wired } from \"capsid\";\n\n// Declares `mirroring` component.\n// HTML elements which have `mirroring` class will be mounted by this component.\n@component(\"mirroring\")\nclass Mirroring {\n  // Wires `dest` property to dom which is selected by `.dest` selector.\n  @wired(\".dest\")\n  dest!: HTMLParagraphElement;\n\n  // Wires `src` property to dom which is selected by `.src` selector.\n  @wired(\".src\")\n  src!: HTMLInputElement;\n\n  // Declares `input` event listener\n  @on(\"input\")\n  onReceiveData() {\n    this.dest.textContent = this.src.value;\n  }\n}\n```\n\n```html\n\u003cdiv class=\"mirroring\"\u003e\n  \u003cinput class=\"src\" /\u003e\n  \u003cp class=\"dest\"\u003e\u003c/p\u003e\n\u003c/div\u003e\n```\n\n`@component(\"mirroring\")` registers the class as the component `mirroring`.\n\n`@wired` binds a dom element to the field which is queried by the given\nselector. `@on(\"input\")` declares the following method is the `input` event\nhandler. In the event handler `src` value is copied to `dest` content, which\nresults the mirroring of the input values to the textContent of `.dest`\nparagraph.\n\n[See the demo][Mirroring Example]\n\n# :cd: Install\n\n## Via npm\n\n    npm install --save capsid\n\nthen:\n\n```js\nimport { component } from \"capsid\";\n```\n\nNote: You need TypeScript for using capsid because it depends on TypeScript\ndecorators. You can easily start using TypeScript by using bundlers like\n[parcel][parcel]\n\n## Via deno.land/x\n\nIf you prefer [Deno](https://deno.land/), you can import capsid via\n`deno.land/x` registry.\n\n```js\nimport { component } from \"https://deno.land/x/capsid@v1.8.2/mod.ts\";\n```\n\n# Decorators\n\n```js\nimport { component, emits, innerHTML, is, on, pub, sub, wired } from \"capsid\";\n```\n\n- `@component(name)`\n  - _class decorator_\n  - registers as a capsid components.\n- `@on(event, { at })`\n  - _method decorator_\n  - registers as an event listener on the component.\n  - `@on.click` is a shorthand for `@on('click')`.\n  - `@on.click.at(selector)` is a shorthand for\n    `@on('click', { at: selector })`.\n- `@emits(event)`\n  - _method decorator_\n  - makes the decorated method an event emitter.\n- `@wired(selector)`\n  - _field decorator_\n  - wires the elements to the decorated field by the given selector.\n  - optionally `@wired.all(selector)`\n- `@is(name)`\n  - _class decorator_\n  - Adds the class name to the given element.\n- `@innerHTML(html: string)`\n  - _class decorator_\n  - Sets the given html string as innerHTML of the element at the mount timing.\n- `@pub(event: string, selector?: string)`\n  - _methods decorator_\n  - Publishes the event to the elements which have `sub:event` class.\n- `@sub(event: string)`\n  - _class decorator_\n  - Adds the `sub:event` class to the given element.\n\n## `@component(name: string)`\n\ncapsid.component(className) is class decorator. With this decorator, you can\nregiter the js class as class component.\n\nThis is a shorthand of `capsid.def('component', Component)`.\n\n```js\nimport { component } from 'capsid'\n\n@component('timer')\nclass Timer {\n  ...definitions...\n}\n```\n\nThe above registers `Timer` class as `timer` component.\n\n## `@on(event: string)`\n\n`@on` is a method decorator. With this decorator, you can register the method as\nthe event handler of the element.\n\n```js\nimport { on, component } from 'capsid'\n\n@component('foo-btn')\nclass FooButton {\n\n  @on('click')\n  onClick (e) {\n    ...definitions...\n  }\n}\n```\n\nThe above binds `onClick` method to its element's 'click' event automatically.\n\nThe above is equivalent of:\n\n```js\nclass FooButton {\n  __mount__ () {\n    this.el.addEventListener('click', e =\u003e {\n      this.onClick(e)\n    })\n  }\n\n  onClick (e) {\n    ...definitions...\n  }\n}\n\ncapsid.def('foo-btn', FooButton)\n```\n\n## `@on(event: string, { at }: { at: string })`\n\n`@on(name, { at: selector })` is a method decorator. It's similar to `@on`, but\nit only handles the event from `selector` in the component.\n\n```js\nimport { on, component } from 'capsid'\n\n@component('btn')\nclass Btn {\n  @on('click', { at: '.btn' })\n  onBtnClick (e) {\n    ...definitions...\n  }\n}\n```\n\nIn the above example, `onBtnClick` method listens to the click event of the\n`.btn` element in the `Btn`'s element.\n\n## `@on.click`\n\n`@on.click` is a shorthand for `@on('click')`.\n\n```js\nclass Foo {\n  @on.click\n  onClick {\n    // handling of the click of the Foo component\n  }\n}\n```\n\n## `@on.click.at(selector: string)`\n\n`@on.click.at(selector)` is a shorthand for `@on('click', { at: selector })`\n\n```js\nclass Foo {\n  @on.click.at(\".edit-button\")\n  onClickAtEditButton() {\n    // handling of the click of the edit button\n  }\n}\n```\n\n**NOTE:** You can add this type of short hand by calling\n`on.useHandler(eventName)`.\n\n```js\non.useHandler(\"change\");\n\nclass Foo {\n  @on.change.at(\".title-input\") // \u003c= This is enabled by the above useHandler call.\n  onChangeAtTitleInput() {\n    // handles the change event of title input field.\n  }\n}\n```\n\n## `@emits(event: string)`\n\n`@emits(eventName)` triggers the event at the end of the method.\n\n```js\nimport { emits, component } from 'capsid'\n\n@component('manager')\nclass Manager {\n  @emits('manager.ended')\n  start() {\n    ...definitions...\n  }\n}\n```\n\nIn the above example, `start` method triggers the `manager.ended` event when it\nfinished. The returns value of the method is passed as `detail` of the event\nobject. So you can pass the data from children to parents.\n\nIf the method returns a promise, then the event is triggered _after_ the promise\nis resolved.\n\n```js\nconst { emits, component } = require('capsid')\n\n@component('manager')\nclass Manager {\n  @emits('manager.ended')\n  start () {\n    ...definitions...\n\n    return promise\n  }\n}\n```\n\nIn the above example, `manager.ended` event is triggered after `promise` is\nresolved. The resolved value of the promise is passed as `detail` of the event\nobject.\n\n## `@wired(selector: string) field`\n\n- @param {string} selector The selector to look up the element in the component\n\nThis wires the decorated field to the element selected by the given selector.\nThe wired element is a unusal dom element (HTMLElement), not a capsid component\ninstance.\n\nIf the selector matches to the multiple elements, then the first one is used.\n\n## `@wired.all(selector: string) field`\n\n- @param {string} selector The selector to look up the elements in the component\n\nThis wires the decorated field to the all elements selected by the given\nselector. This is similar to `@wired` decorator, but it wires all the elements,\nnot the first one.\n\n## `@is(...classNames: string[])`\n\nAdds the given class names to the element when it's mounted.\n\n```ts\n@component(\"foo\")\n@is(\"bar-observer\")\nclass Foo {\n}\n\nmake(\"foo\", document.body);\n\ndocument.body.classList.contains(\"bar-observer\");\n// =\u003e true\n```\n\nThis decorator is useful when a component has several different roles. You can\nadds the role of the component by specifying `@is('class-name')`.\n\n## `@innerHTML(html: string)`\n\nSets the given html string as the innerHTML of the element at mount timing.\n\n```ts\n@component(\"foo\")\n@innerHTML(`\n  \u003cp\u003ehello\u003c/p\u003e\n`)\nclass Foo {\n}\n\nmake(\"foo\", document.body);\n\ndocument.body.innerHTML;\n// =\u003e \u003cp\u003ehello\u003c/p\u003e\n```\n\n## `@pub(event: string)`\n\nThe method dispatches the `event` to the elements which have `sub:{event}`\nclass. For example, if the method has `@pub('foo')`, then it dispatches `foo`\nevent to the elements which have `sub:foo` class. The dispatched events don't\nbuble up the dom tree.\n\n```ts\n@component(\"my-comp\")\nclass MyComp {\n  @pub(\"foo\")\n  method() {\n    // something ...\n  }\n}\n```\n\nThe returned value or resolved value of the decorator becomes the `detail` prop\nof the dispatched custom event.\n\n## `@pub(event: string, selector: string)`\n\nThe method dispatches `event` to the given `selector`.\n\n```ts\n@component(\"my-comp\")\nclass MyComp {\n  @pub(\"foo\", \"#foo-receiver\")\n  method() {\n    // something ...\n  }\n}\n```\n\n## `@sub(event: string)`\n\nThis class decorator adds the `sub:event` class to the given component. For\nexample if you use `@sub('foo')`, the component have `sub:foo` class, which\nmeans this class becomes the subscriber of `foo` event in combination with\n`@pub('foo')` decorator.\n\n```ts\n@component(\"my-comp\")\n@sub(\"foo\")\nclass MyComp {\n  @on(\"foo\")\n  handler() {\n    // ... do something\n  }\n}\n```\n\n# APIs\n\nThese are advanced APIs of capsid. You usually don't need these APIs for\nbuilding an app, but these could be useful if you write capsid plugins or\nreusable capsid modules. These APIs are used for building decorators of capsid.\n\n```js\nimport { def, get, install, make, mount, prep, unmount } from \"capsid\";\n```\n\n- `def(name, constructor)`\n  - Registers class-component.\n- `prep([name], [element])`\n  - Initialize class-component on the given range.\n- `make(name, element)`\n  - Initializes the element with the component of the given name and return the\n    coelement instance.\n- `mount(Constructor, element)`\n  - Initializes the element with the component of the given class and return the\n    coelement.\n- `unmount(name, element)`\n  - unmount the component from the element by its name.\n- `get(name, element)`\n  - Gets the coelement instance from the given element.\n- `install(capsidModule, options)`\n  - installs the capsid module with the given options.\n\n## `def(name, constructor)`\n\n- @param {string} name The class name of the component\n- @param {Function} constructor The constructor of the coelement of the\n  component\n\nThis registers `constructor` as the constructor of the coelement of the class\ncomponent of the given name `name`. The constructor is called with a jQuery\nobject of the dom as the first parameter and the instance of the coelement is\nattached to the dom. The instance of coelement can be obtained by calling\n`elem.cc.get(name)`.\n\nExample:\n\n```js\nclass TodoItem {\n  // ...behaviours...\n}\n\ncapsid.def(\"todo-item\", TodoItem);\n```\n\n```html\n\u003cli class=\"todo-item\"\u003e\u003c/li\u003e\n```\n\n## `prep([name], [element])`\n\n- @param {string} [name] The capsid component name to intialize\n- @param {HTMLElement} [element] The range to initialize\n\nThis initializes the capsid components of the given name under the given\nelement. If the element is omitted, it initializes in the entire page. If the\nname is omitted, then it initializes all the registered class components in the\ngiven range.\n\n## `make(name, element)`\n\n- @param {string} name The capsid component name to initialize\n- @param {HTMLElement} element The element to initialize\n- @return {\u003cComponent\u003e} created coelement\n\nInitializes the element as the capsid component and returns the coelement\ninstance.\n\n```js\nconst timer = make(\"timer\", dom);\n```\n\n## `mount(Constructor, element)`\n\n- @param {Function} Constructor The constructor which defines the capsid\n  component\n- @param {HTMLElemen} element The element to mount the component\n- @return {\u003cConstructor\u003e} The created coelement\n\nInitializes the element with the component of the given class and return the\ncoelement.\n\n```js\nclass Component {\n  __mount__ () {\n    this.el.foo = 1\n  }\n}\n\nconst div = document.createElement('div')\n\ncapsid.mount(Component, div)\n\ndiv.foo === 1 # =\u003e true\n```\n\nUsually you don't need to use this API. If you're writing library using capsid,\nyou might sometimes need to create an unnamed component and need this API then.\n\n## `unmount(name, element)`\n\n- @param {string} name The component name\n- @param {HTMLElement} element The element\n\nUnmounts the component of the given name from the element.\n\nExample:\n\n```js\n@component(\"foo\")\nclass Foo {\n  @on(\"input\")\n  remove() {\n    unmount(\"foo\", this.el);\n  }\n}\n```\n\nThe above example unmounts itself when it receives `input` event.\n\n## `get(name, element)`\n\n- @param {string} name The capsid component name to get\n- @param {HTMLElement} element The element\n- @return The coelement instance\n\nGets the component instance from the element.\n\n```js\nconst timer = capsid.get(\"timer\", el);\n```\n\nThe above gets timer coelement from `el`, which is instance of `Timer` class.\n\n### `install(capsidModule[, options])`\n\n- @param {CapsidModule} capsidModule The module to install\n- @param {Object} options The options to pass to the module\n\nThis installs the capsid module.\n\n```js\ncapsid.install(require(\"capsid-popper\"), { name: \"my-app-popper\" });\n```\n\nSee [capsid-module][capsid-module] repository for details.\n\n# Plugins\n\n## Debug plugin\n\n`debug plugin` outputs information useful for debugging capsid app.\n\n### Install\n\nVia npm:\n\n```js\nimport { install } from \"capsid\";\nimport debug from \"capsid/debug\";\ninstall(debug);\n```\n\nVia CDN:\n\n```html\n\u003cscript src=\"https://unpkg.com/capsid\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://unpkg.com/capsid/dist/capsid-debug.js\"\u003e\u003c/script\u003e\n\u003cscript\u003ecapsid.install(capsidDebugPlugin)\u003c/script\u003e\n```\n\nAnd you'll get additional debug information in console.\n\n\u003cimg src=\"http://capsidjs.github.io/capsid/asset/ss-debug.png\" /\u003e\n\n## Outside Events Plugin\n\n### Install\n\nVia npm:\n\n```js\nimport { install } from \"capsid\";\nimport outside from \"capsid/outside\";\ninstall(outside);\n```\n\nVia cdn:\n\n```html\n\u003cscript src=\"https://unpkg.com/capsid\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://unpkg.com/capsid/dist/capsid-outside-events.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\ncapsid.install(capsidOutsideEventsPlugin)\n\u003c/script\u003e\n```\n\nWith `outside-events-plugin`, you can bind methods to events _outside_ of your\ncoponent's element. (This event need to bubble up to `document`)\n\n```js\n@component(\"modal\")\nclass Modal {\n  @on.outside(\"click\")\n  close() {\n    this.el.classList.remove(\"is-shown\");\n  }\n\n  open() {\n    this.el.classList.add(\"is-shown\");\n  }\n}\n```\n\nThe above `modal` component gets `is-shown` class removed from the element when\nthe outside of modal is clicked.\n\n#### prior art of capsid outside plugin\n\n- [jQuery outside events](https://github.com/cowboy/jquery-outside-events)\n- [react-onclickoutside](https://github.com/Pomax/react-onclickoutside)\n\n# Initialization\n\nThere are 2 ways to initialize components:\n\n1. [When document is ready][DOMContentLoaded] (automatic).\n2. When `capsid.prep()` is called (manual).\n\nAll components are initialized automatically when document is ready. You don't\nneed to care about those elements which exist before document is ready. See\n[Hello Example][Hello Example] or [Clock Example][Clock Example] for example.\n\nIf you add elements after document is ready (for example, after ajax requests),\ncall `capsid.prep()` and that initializes all the components.\n\n```js\nconst addPartOfPage = async () =\u003e {\n  const { html } = await axios.get('path/to/something.html')\n\n  containerElemenent.innerHTML = html\n\n  capsid.prep() // \u003c= this initializes all the elements which are not yet initialized.\n})\n```\n\n# Capsid Lifecycle\n\nCapsid has 2 lifecycle events: `mount` and `unmount`.\n\n```\nnothing -\u003e [mount] -\u003e component mounted -\u003e [unmount] -\u003e nothing\n```\n\n## Lifecycle events\n\n- `mount`\n  - HTML elements are mounted by the components.\n  - An element is coupled with the corresponding coelement and they start\n    working together.\n\n- `unmount`\n  - An element is decouple with the coelement.\n  - All events are removed and coelement is discarded.\n  - You need to call `unmount(class, element)` to trigger the unmount event.\n\n## Explanation of `mount`\n\nAt `mount` event, these things happen.\n\n- The component class's `instance` (coelement) is created.\n- `instance`.el is set to corresponding dom element.\n- `before mount`-hooks are invoked.\n  - This includes the initialization of event handlers, class names, innerHTML,\n    and custom plugin's hooks.\n- if `instance` has **mount** method, then `instance.__mount__()` is called.\n\nThe above happens in this order. Therefore you can access `this.el` and you can\ninvoke the events at `this.el` in `__mount__` method.\n\n## Lifecycle Methods\n\n### `constructor`\n\nThe constructor is called at the start of `mount`ing. You cannot access\n`this.el` here. If you need to interact with `this.el`, use `__mount__` method.\n\n### `__mount__`\n\n`__mount__()` is called at the **end** of the mount event. When it is called,\nthe dom element and event handlers are ready and available through `this.el`.\n\n### `__unmount__`\n\n`__unmount__()` is called when component is unmounted. If your component put\nresources on global space, you should discard them here to avoid memory leak.\n\n# Coelement\n\nCoelement is the instance of Component class, which is attached to html element.\nYou can get coelement from the element using `get` API.\n\n# History\n\n- 2022-01-03 v1.8.1 Modify npm package contents. #212\n- 2022-01-03 v1.8.0 Migrated to Deno. #212\n- 2020-04-02 v1.7.0 Better make/get/unmount types.\n- 2020-03-30 v1.6.2 Fix submodule export for TypeScript.\n- 2020-03-28 v1.6.1 Fix debug plugin.\n- 2020-03-28 v1.6.0 Automatic intialization of components inside `@innerHTML`.\n- 2020-03-21 v1.5.0 Extend `@pub` decorator and remove `@notifies`.\n- 2020-03-21 v1.4.0 Add `@innerHTML` decorator.\n- 2020-03-15 v1.3.0 Add `@pub` and `@sub` decorators.\n- 2020-03-14 v1.2.0 Add `@is` decorator.\n- 2020-03-13 v1.1.0 Add type declaration.\n- 2020-03-12 v1.0.0 Support TypeScript decorators. Drop babel decorators\n  support.\n- 2019-06-09 v0.29.2 Throw error when empty selector is given (`@notifies`)\n- 2018-12-01 v0.29.0 Switch to TypeScript.\n- 2018-11-22 v0.28.0 Switch to new decorator. Remove jquery-plugin.\n- 2018-08-07 v0.26.1 Fix bug of unmount and on handler.\n- 2018-07-12 v0.26.0 Add debug log contents.\n- 2018-06-22 v0.25.0 Add `@on.useHandler`.\n- 2018-06-22 v0.24.0 Add `@on.click.at`.\n- 2018-05-20 v0.23.5 Fix unmount bug.\n- 2018-04-18 v0.23.4 Fix unmount bug.\n- 2018-04-10 v0.23.0 Change debug format.\n- 2018-04-09 v0.22.0 Rename **init** to **mount**.\n- 2018-04-08 v0.21.0 Add `unmount`.\n- 2018-04-04 v0.20.3 Change initialized class name.\n- 2018-03-08 v0.20.0 Add install function.\n- 2017-12-31 v0.19.0 Add wired, wired.all and wired.component decorators.\n- 2017-12-05 v0.18.3 Add an error message.\n- 2017-10-12 v0.18.0 Add Outside Events plugin.\n- 2017-10-01 v0.17.0 Add Debug plugin.\n- 2017-09-09 v0.16.0 Rename `@emit` to `@emits` and `@pub` to `@notifies`\n- 2017-09-06 v0.15.1 Change component init sequence.\n- 2017-09-05 v0.15.0 Add `mount` API. Remove `init` API.\n- 2017-08-04 v0.14.0 Make `@on` listeners ready at **init** call.\n- 2017-08-03 v0.13.0 Add pub decorator.\n- 2017-07-15 v0.12.0 Add wire.$el and wire.elAll to jquery plugin.\n- 2017-07-13 v0.11.0 Add wire.el and wire.elAll.\n- 2017-07-11 v0.10.0 Add emit.first rename emit.last to emit.\n- 2017-07-10 v0.9.0 Add on.click shorthand.\n- 2017-03-01 v0.8.0 Modify init sequence.\n- 2017-02-26 v0.7.0 Add static capsid object to each coelement class.\n- 2017-02-26 v0.6.0 static **init** rule.\n- 2017-02-25 v0.5.0 coelem.capsid, initComponent APIs.\n- 2017-01-19 v0.3.0 API reorganization.\n- 2017-01-19 v0.2.2 Rename to capsid.\n- 2017-01-17 v0.1.1 Add plugin system.\n\n# History of class-component.js (former project)\n\n- 2017-01-02 v13.0.0 Add **init** instead of init.\n- 2017-01-01 v12.1.1 Fix bug of event bubbling.\n- 2017-01-01 v12.1.0 Remove @emit.first. Use native dispatchEvent.\n- 2016-12-31 v12.0.0 Remove **cc_init** feature. Add init feature.\n- 2016-09-30 v10.7.1 Refactor @emit.last decorator\n- 2016-09-11 v10.7.0 Add @on(event, {at}) @emit.first and @emit.last\n- 2016-08-22 v10.6.2 Refactor the entrypoint.\n- 2016-08-22 v10.6.1 Improved the event listener registration process.\n- 2016-08-20 v10.6.0 Cleaned up some private APIs.\n- 2016-08-20 v10.5.0 Cleaned up codebase and made the bundle smaller. Remove\n  some private APIs.\n- 2016-08-17 v10.4.1 Made built version smaller.\n- 2016-08-16 v10.4.0 Switched to babel-preset-es2015-loose.\n- 2016-08-16 v10.3.0 Modified bare @wire decorator.\n- 2016-08-02 v10.2.0 Added bare @component decorator.\n- 2016-07-21 v10.1.0 Added @wire decorator.\n- 2016-06-19 v10.0.0 Removed deprecated decorators `@event` and `@trigger`, use\n  `@on` and `@emit` instead.\n- 2016-06-09 v9.2.0 Fixed bug of `@emit().last` decorator.\n\n# Examples\n\n- :wave: [Hello Example][Hello Example]\n- :stopwatch: [Clock Example][Clock Example]\n- :level_slider: [Counter Example][Counter Example]\n- :butterfly: [Mirroring Example][Mirroring Example]\n\n- [todomvc2](https://github.com/capsidjs/todomvc2)\n  - [TodoMVC](http://todomvc.com/) in capsid.\n\n# License\n\nMIT\n\n[flux]: http://facebook.github.io/flux\n[evex]: http://github.com/capsidjs/evex\n[Hello Example]: https://codesandbox.io/s/hello-world-capsidjs-example-k5dgl\n[Clock Example]: https://codesandbox.io/s/clock-capsidjs-example-i9d7k\n[Counter Example]: https://codesandbox.io/s/km023p21nv\n[Mirroring Example]: https://codesandbox.io/s/p7m3xv3mvq\n[DOMContentLoaded]: https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded\n[capsid-module]: https://github.com/capsidjs/capsid-module\n[parcel]: https://parceljs.org/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcapsidjs%2Fcapsid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcapsidjs%2Fcapsid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcapsidjs%2Fcapsid/lists"}