element.js

import element from 'element.js'

Description

The element helper automates many utility features that often have to be added to every new custom element, like dispatching to different handler methods depending on the name of a changed attribute or adding getters and setters for these attributes.

Basic Usage

element(class MyElement extends HTMLElement { constructor() { super() console.log("An element walks into a bar...") } })

Features

Attributes

The static attributes property, when present, is used to automatically add the static observedAttributes property for the custom element API, as well as define getters and setters for the listed attributes.

A pair of filters can be given to modify the value after getting or before setting it. This can be used to convert between the string values that attributes restrict us to and a more sensible representation as well as some validation (attributes can be changed externally, after all).

Object keys in camelCase will be converted to kebab-case before being used as attribute names in the auto-generated observedAttributes.

The rules are:

element(class extends HTMLElement { static attributes = { plain = true, filtered = { get(string) { return Number(string) } set(value) { return Math.floor(value*100+0.5)/100 } }, plainReadOnly = { set: false }, } })

Change Methods

The attributeChangedCallback method is added automatically to the class. This auto-generated callback will first look up a ${attributeName}Changed method and call it, if found, with the old and new values as arguments. Then it will look for a changed method and call it with the same arguments as attributeChangedCallback normally receives.

Attribute names will be converted from camelCase to kebab-case when needed before being used to form a method name to look up. Changing an attribute foo-bar will look for a fooBarChanged method.

element(class extends HTMLElement { static attributes = { fooBar = true } fooBarChanged(oldValue, newValue) { console.log(`foo-bar changed from ${oldValue} to ${newValue}`) } })

Batched Methods

Certain methods, like re-rendering the content of a component should often happen in response to events that can happen repeatedly, or in response to many different events that can all happen at once.

To avoid having to repeatedly add complicated checks to handle these event bursts, element introduces the concept of dollar-methods.

element(class extends HTMLElement { $render() { console.warn("Full Re-render...") } })

Any method with a name starting with $ will automatically have a sibling-method defined, with the dollar removed. Each time this auto-generated method is called, its argument list will be pushed to an array and a call of the original dollar-method will be scheduled as a micro-task.

The original method will then be called with the argument-lists of the individual calls to its dollar-less counterpart all at once.

It is of course still possible to manually call the dollar-method when immediate execution is wanted.

Note how in the following example, all three change methods would be called in rapid succession if the browser applies the custom element class to an element it found on the page with all three attributes foo, bar and baz defined.

element(class extends HTMLElement { $render() { console.warn("Full Re-render...") } fooChanged() { this.render() } barChanged() { this.render() } bazChanged() { this.render() } })

Here, this.render() will not instantly re-render the whole component but instead schedule the re-render in a micro-task, potentially avoiding lots of repeated work.