
Research
/Security News
9 Malicious NuGet Packages Deliver Time-Delayed Destructive Payloads
Socket researchers discovered nine malicious NuGet packages that use time-delayed payloads to crash applications and corrupt industrial control systems.
This example illustrates the basic ideas of capsid.
import { on, wired, component } import "capsid";
// Declares `mirroring` component.
// HTML elements which have `mirroring` class will be mounted by this component.
@component("mirroring")
class Mirroring {
// Wires `dest` property to dom which is selected by `.dest` selector.
@wired(".dest")
dest!: HTMLParagraphElement;
// Wires `src` property to dom which is selected by `.src` selector.
@wired(".src")
src!: HTMLInputElement;
// Declares `input` event listener
@on("input")
onReceiveData() {
this.dest.textContent = this.src.value;
}
}
<div class="mirroring">
<input class="src" />
<p class="dest"></p>
</div>
@component("mirroring") registers the class as the component mirroring.
@wired binds a dom element to the field which is queried by the given
selector. @on("input") declares the following method is the input event
handler. In the event handler src value is copied to dest content, which
results the mirroring of the input values to the textContent of .dest
paragraph.
npm install --save capsid
then:
import { component } from "capsid";
Note: You need TypeScript for using capsid because it depends on TypeScript decorators. You can easily start using TypeScript by using bundlers like parcel
If you prefer Deno, you can import capsid via
deno.land/x registry.
import { component } from "https://deno.land/x/capsid@v1.8.2/mod.ts";
import { component, emits, innerHTML, is, on, pub, sub, wired } from "capsid";
@component(name)
@on(event, { at })
@on.click is a shorthand for @on('click').@on.click.at(selector) is a shorthand for
@on('click', { at: selector }).@emits(event)
@wired(selector)
@wired.all(selector)@is(name)
@innerHTML(html: string)
@pub(event: string, selector?: string)
sub:event class.@sub(event: string)
sub:event class to the given element.@component(name: string)capsid.component(className) is class decorator. With this decorator, you can regiter the js class as class component.
This is a shorthand of capsid.def('component', Component).
import { component } from 'capsid'
@component('timer')
class Timer {
...definitions...
}
The above registers Timer class as timer component.
@on(event: string)@on is a method decorator. With this decorator, you can register the method as
the event handler of the element.
import { on, component } from 'capsid'
@component('foo-btn')
class FooButton {
@on('click')
onClick (e) {
...definitions...
}
}
The above binds onClick method to its element's 'click' event automatically.
The above is equivalent of:
class FooButton {
__mount__ () {
this.el.addEventListener('click', e => {
this.onClick(e)
})
}
onClick (e) {
...definitions...
}
}
capsid.def('foo-btn', FooButton)
@on(event: string, { at }: { at: string })@on(name, { at: selector }) is a method decorator. It's similar to @on, but
it only handles the event from selector in the component.
import { on, component } from 'capsid'
@component('btn')
class Btn {
@on('click', { at: '.btn' })
onBtnClick (e) {
...definitions...
}
}
In the above example, onBtnClick method listens to the click event of the
.btn element in the Btn's element.
@on.click@on.click is a shorthand for @on('click').
class Foo {
@on.click
onClick {
// handling of the click of the Foo component
}
}
@on.click.at(selector: string)@on.click.at(selector) is a shorthand for @on('click', { at: selector })
class Foo {
@on.click.at(".edit-button")
onClickAtEditButton() {
// handling of the click of the edit button
}
}
NOTE: You can add this type of short hand by calling
on.useHandler(eventName).
on.useHandler("change");
class Foo {
@on.change.at(".title-input") // <= This is enabled by the above useHandler call.
onChangeAtTitleInput() {
// handles the change event of title input field.
}
}
@emits(event: string)@emits(eventName) triggers the event at the end of the method.
import { emits, component } from 'capsid'
@component('manager')
class Manager {
@emits('manager.ended')
start() {
...definitions...
}
}
In the above example, start method triggers the manager.ended event when it
finished. The returns value of the method is passed as detail of the event
object. So you can pass the data from children to parents.
If the method returns a promise, then the event is triggered after the promise is resolved.
const { emits, component } = require('capsid')
@component('manager')
class Manager {
@emits('manager.ended')
start () {
...definitions...
return promise
}
}
In the above example, manager.ended event is triggered after promise is
resolved. The resolved value of the promise is passed as detail of the event
object.
@wired(selector: string) fieldThis wires the decorated field to the element selected by the given selector. The wired element is a unusal dom element (HTMLElement), not a capsid component instance.
If the selector matches to the multiple elements, then the first one is used.
@wired.all(selector: string) fieldThis wires the decorated field to the all elements selected by the given
selector. This is similar to @wired decorator, but it wires all the elements,
not the first one.
@is(...classNames: string[])Adds the given class names to the element when it's mounted.
@component("foo")
@is("bar-observer")
class Foo {
}
make("foo", document.body);
document.body.classList.contains("bar-observer");
// => true
This decorator is useful when a component has several different roles. You can
adds the role of the component by specifying @is('class-name').
@innerHTML(html: string)Sets the given html string as the innerHTML of the element at mount timing.
@component("foo")
@innerHTML(`
<p>hello</p>
`)
class Foo {
}
make("foo", document.body);
document.body.innerHTML;
// => <p>hello</p>
@pub(event: string)The method dispatches the event to the elements which have sub:{event}
class. For example, if the method has @pub('foo'), then it dispatches foo
event to the elements which have sub:foo class. The dispatched events don't
buble up the dom tree.
@component("my-comp")
class MyComp {
@pub("foo")
method() {
// something ...
}
}
The returned value or resolved value of the decorator becomes the detail prop
of the dispatched custom event.
@pub(event: string, selector: string)The method dispatches event to the given selector.
@component("my-comp")
class MyComp {
@pub("foo", "#foo-receiver")
method() {
// something ...
}
}
@sub(event: string)This class decorator adds the sub:event class to the given component. For
example if you use @sub('foo'), the component have sub:foo class, which
means this class becomes the subscriber of foo event in combination with
@pub('foo') decorator.
@component("my-comp")
@sub("foo")
class MyComp {
@on("foo")
handler() {
// ... do something
}
}
These are advanced APIs of capsid. You usually don't need these APIs for building an app, but these could be useful if you write capsid plugins or reusable capsid modules. These APIs are used for building decorators of capsid.
import { def, get, install, make, mount, prep, unmount } from "capsid";
def(name, constructor)
prep([name], [element])
make(name, element)
mount(Constructor, element)
unmount(name, element)
get(name, element)
install(capsidModule, options)
def(name, constructor)This registers constructor as the constructor of the coelement of the class
component of the given name name. The constructor is called with a jQuery
object of the dom as the first parameter and the instance of the coelement is
attached to the dom. The instance of coelement can be obtained by calling
elem.cc.get(name).
Example:
class TodoItem {
// ...behaviours...
}
capsid.def("todo-item", TodoItem);
<li class="todo-item"></li>
prep([name], [element])This initializes the capsid components of the given name under the given element. If the element is omitted, it initializes in the entire page. If the name is omitted, then it initializes all the registered class components in the given range.
make(name, element)Initializes the element as the capsid component and returns the coelement instance.
const timer = make("timer", dom);
mount(Constructor, element)Initializes the element with the component of the given class and return the coelement.
class Component {
__mount__ () {
this.el.foo = 1
}
}
const div = document.createElement('div')
capsid.mount(Component, div)
div.foo === 1 # => true
Usually you don't need to use this API. If you're writing library using capsid, you might sometimes need to create an unnamed component and need this API then.
unmount(name, element)Unmounts the component of the given name from the element.
Example:
@component("foo")
class Foo {
@on("input")
remove() {
unmount("foo", this.el);
}
}
The above example unmounts itself when it receives input event.
get(name, element)Gets the component instance from the element.
const timer = capsid.get("timer", el);
The above gets timer coelement from el, which is instance of Timer class.
install(capsidModule[, options])This installs the capsid module.
capsid.install(require("capsid-popper"), { name: "my-app-popper" });
See capsid-module repository for details.
debug plugin outputs information useful for debugging capsid app.
Via npm:
import { install } from "capsid";
import debug from "capsid/debug";
install(debug);
Via CDN:
<script src="https://unpkg.com/capsid"></script>
<script src="https://unpkg.com/capsid/dist/capsid-debug.js"></script>
<script>capsid.install(capsidDebugPlugin)</script>
And you'll get additional debug information in console.
Via npm:
import { install } from "capsid";
import outside from "capsid/outside";
install(outside);
Via cdn:
<script src="https://unpkg.com/capsid"></script>
<script src="https://unpkg.com/capsid/dist/capsid-outside-events.js"></script>
<script>
capsid.install(capsidOutsideEventsPlugin)
</script>
With outside-events-plugin, you can bind methods to events outside of your
coponent's element. (This event need to bubble up to document)
@component("modal")
class Modal {
@on.outside("click")
close() {
this.el.classList.remove("is-shown");
}
open() {
this.el.classList.add("is-shown");
}
}
The above modal component gets is-shown class removed from the element when
the outside of modal is clicked.
There are 2 ways to initialize components:
capsid.prep() is called (manual).All components are initialized automatically when document is ready. You don't need to care about those elements which exist before document is ready. See Hello Example or Clock Example for example.
If you add elements after document is ready (for example, after ajax requests),
call capsid.prep() and that initializes all the components.
const addPartOfPage = async () => {
const { html } = await axios.get('path/to/something.html')
containerElemenent.innerHTML = html
capsid.prep() // <= this initializes all the elements which are not yet initialized.
})
Capsid has 2 lifecycle events: mount and unmount.
nothing -> [mount] -> component mounted -> [unmount] -> nothing
mount
unmount
unmount(class, element) to trigger the unmount event.mountAt mount event, these things happen.
instance (coelement) is created.instance.el is set to corresponding dom element.before mount-hooks are invoked.
instance has mount method, then instance.__mount__() is called.The above happens in this order. Therefore you can access this.el and you can
invoke the events at this.el in __mount__ method.
constructorThe constructor is called at the start of mounting. You cannot access
this.el here. If you need to interact with this.el, use __mount__ method.
__mount____mount__() is called at the end of the mount event. When it is called,
the dom element and event handlers are ready and available through this.el.
__unmount____unmount__() is called when component is unmounted. If your component put
resources on global space, you should discard them here to avoid memory leak.
Coelement is the instance of Component class, which is attached to html element.
You can get coelement from the element using get API.
@innerHTML.@pub decorator and remove @notifies.@innerHTML decorator.@pub and @sub decorators.@is decorator.@notifies)@on.useHandler.@on.click.at.unmount.@emit to @emits and @pub to @notifiesmount API. Remove init API.@on listeners ready at init call.@event and @trigger, use
@on and @emit instead.@emit().last decorator.:wave: Hello Example
:stopwatch: Clock Example
:level_slider: Counter Example
:butterfly: Mirroring Example
MIT
FAQs
Declarative DOM programming library based on TypeScript decorators
We found that capsid demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
Socket researchers discovered nine malicious NuGet packages that use time-delayed payloads to crash applications and corrupt industrial control systems.

Security News
Socket CTO Ahmad Nassri discusses why supply chain attacks now target developer machines and what AI means for the future of enterprise security.

Security News
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.