@vonage/element-f
Version:
A functional shim to custom element definition
97 lines (74 loc) • 2.9 kB
Markdown
# element-f
A functional shim to custom element definition.
### Installation
```
npm i @vonage/element-f
```
### Basics
In order to define a custom-element, you only need one definition function:
```javascript
import elementF from "@voange/element-f";
const MyElement = elementF(()=> {
// Your logic goes here
const shadow = this.attachShadow({mode: 'open'});
});
```
To tap into lifecycle events, this function can use the "life" event emitter:
```javascript
const MyElement = elementF((life)=> {
const shadow = this.attachShadow({mode: 'open'});
// Listen once to when this component connects to a document
life.once('connect', ()=> shadow.innerHTML = `I'm Alive!`);
});
```
The "life" event emitter supports three methods:
* **`once(name, fn)`<br/>`on(name, fn)`** - Registers **`fn`** for events of name **`name`**. **`once()`** will invoke **fn** once.
* **`name`** - The name of the event to listen to
* **`fn(payload)`** - The function to be called when an event occurs
* **`payload`** - An object containing information regarding the event
* **`off(name, fn)`** - Removes an event handler previously registered using **on** or **once**.
The following events are thrown:
* **`connect`** - Fired upon `connectedCallback`. Delivers no payload.
* **`disconnect`** - Fired upon `disconnectedCallback`. Delivers no payload.
* **`attribute`** - Fired when an observed attribute changes. Delivers **name**, **previousValue** and **newValue** as payload.
To observe attributes, just add their list to `elementF` call:
```javascript
const MyElement = elementF((life)=> {
life.on('attribute', ({ name, previousValue, newValue })=> {
// name can be "one" or "two"
});
}, ["one", "two"]);
```
#### Usage Examples
To define a custom element using standard class notation, you'd write something like:
```javascript
class MyButton extends HTMLElement {
constructor(){
super();
console.log(`I'm alive!`);
}
static get observedAttributes(){
return ['disabled'];
}
attributeChangedCallback(name, oldValue, newValue) {
this.classList.toggle('disabled', newValue);
}
connectCallback() {
this.innerHTML = "<b>I'm an x-foo-with-markup!</b>";
}
}
```
To defining the same element using **element-f** would look like this:
```javascript
const MyButton = elementF((life)=> {
life.on('connect', ()=> {
this.innerHTML = "<b>I'm an x-foo-with-markup!</b>";
});
life.on('attribute', ({ name, newValue, oldValue })=> {
this.classList.toggle('disabled', newValue);
});
console.log(`I'm alive!`);
}, ['disabled']);
```
### What does Element-F solve?
**Element-F** supplies a stylistic framework, not a fundamental solution to a problem. If you're happy with OOP-styled constructs, you would probably not draw much enjoyment from using it :)