An open API service indexing awesome lists of open source software.

https://github.com/lastmjs/functional-element

Functional custom elements
https://github.com/lastmjs/functional-element

Last synced: 3 months ago
JSON representation

Functional custom elements

Awesome Lists containing this project

README

        

[![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-element) [![devDependency Status](https://david-dm.org/lastmjs/functional-element/dev-status.svg)](https://david-dm.org/lastmjs/functional-element?type=dev)

# 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

```bash
npm install functional-element
```

## Use

`functional-element` produces bonafide custom elements. Use them as follows:

```html





```

Create them as follows:

```javascript
import { html, customElement } from 'functional-element';

customElement('example-element', ({ constructing, hello }) => {
if (constructing) {
return {
hello: 'world!'
};
}

return html`

${hello}

`;
});
```

### Lifecycle

```javascript
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`

It's the cycle of life!

`;
});
```

## Properties

```javascript
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:

${regularProp}

computedProp:
${computedProp()}

`;
});
```

## Listening to events

```javascript
import { html, customElement } from 'functional-element';

customElement('example-element', ({ constructing, update, count }) => {
if (constructing) {
return {
count: 0
};
}

return html`
update({ count: count + 1 })}>${count}
`;
});
```

## Dispatching events

```javascript
import { html, customElement } from 'functional-element';

customElement('example-element', ({ constructing, element, count }) => {
if (constructing) {
return {
count: 0
};
}

return html`
increment(element, count)}>${count}
`;
});

function increment(element, count) {
element.dispatch(new CustomEvent('increment', {
detail: {
count: count + 1
}
}));
}
```
## Async

```javascript
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));
}
```