functional-element
v0.0.18
Published
[![npm version](https://img.shields.io/npm/v/functional-element.svg?style=flat)](https://www.npmjs.com/package/functional-element) [![dependency Status](https://david-dm.org/lastmjs/functional-element/status.svg)](https://david-dm.org/lastmjs/functional-e
Downloads
7
Readme
functional-element
functional-element
exposes the custom element API in a functional manner. It allows you to express your custom element's behavior as a function. The custom element lifecycle is exposed through parameters to your function. You simply return a template or props as needed. Templating is currently handled by lit-html
. Hook up event listeners with simple functions. No more classes, methods, or inheritance.
Live demo
Tic tac toe demo: https://functional-tic-tac-toe.netlify.com
Tic tac toe code: https://github.com/lastmjs/tic-tac-toe
Calculator demo: https://mwad-functional-element.netlify.com
Calculator code: https://github.com/lastmjs/mwad-functional-element
Installation
npm install functional-element
Use
functional-element
produces bonafide custom elements. Use them as follows:
<!DOCTYPE html>
<html>
<head>
<script type="module" src="example-element.js"></script>
</head>
<body>
<example-element></example-element>
</body>
</html>
Create them as follows:
import { html, customElement } from 'functional-element';
customElement('example-element', ({ constructing, hello }) => {
if (constructing) {
return {
hello: 'world!'
};
}
return html`
<div>${hello}</div>
`;
});
Lifecycle
import { html, customElement } from 'functional-element';
customElement('example-element', ({ constructing, connecting, disconnecting, adopting }) => {
if (constructing) {
console.log(`We're in the constructor!`);
}
if (connecting) {
console.log(`We're in the connectedCallback!`);
}
if (disconnecting) {
console.log(`We're in the disconnectedCallback!`);
}
if (adopting) {
console.log(`We're in the adopted callback!`);
}
return html`
<div>It's the cycle of life!</div>
`;
});
Properties
import { html, customElement } from 'functional-element';
customElement('example-element', ({ constructing, regularProp, computedProp }) => {
if (constructing) {
return {
regularProp: `Just your average property`,
computedProp: () => {
return `This property was made by a function`;
}
};
}
return html`
regularProp: <div>${regularProp}</div>
computedProp: <div>${computedProp()}</div>
`;
});
Listening to events
import { html, customElement } from 'functional-element';
customElement('example-element', ({ constructing, update, count }) => {
if (constructing) {
return {
count: 0
};
}
return html`
<button @click=${() => update({ count: count + 1 })}>${count}</button>
`;
});
Dispatching events
import { html, customElement } from 'functional-element';
customElement('example-element', ({ constructing, element, count }) => {
if (constructing) {
return {
count: 0
};
}
return html`
<button @click=${() => increment(element, count)}>${count}</button>
`;
});
function increment(element, count) {
element.dispatch(new CustomEvent('increment', {
detail: {
count: count + 1
}
}));
}
Async
import { html, customElement } from 'functional-element';
customElement('example-element', async ({ constructing, update, count }) => {
if (constructing) {
return {
count: 0
};
}
const newCount = await increment(count);
return html`
count: ${count}
`;
});
async function increment(count) {
await wait(5000);
return count + 1;
}
async function wait(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}