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

https://github.com/substrate-system/web-component

Minimal parent web component to inherit from
https://github.com/substrate-system/web-component

Last synced: about 1 year ago
JSON representation

Minimal parent web component to inherit from

Awesome Lists containing this project

README

          

# web component
![tests](https://github.com/substrate-system/web-component/actions/workflows/nodejs.yml/badge.svg)
[![types](https://img.shields.io/npm/types/@substrate-system/web-component?style=flat-square)](README.md)
[![module](https://img.shields.io/badge/module-ESM%2FCJS-blue?style=flat-square)](README.md)
[![semantic versioning](https://img.shields.io/badge/semver-2.0.0-blue?logo=semver&style=flat-square)](https://semver.org/)
[![dependencies](https://img.shields.io/badge/dependencies-zero-brightgreen.svg?style=flat-square)](package.json#L33)
[![install size](https://flat.badgen.net/packagephobia/install/@substrate-system/web-component?cache-control=no-cache)](https://packagephobia.com/result?p=@substrate-system/web-component)
[![Common Changelog](https://nichoth.github.io/badge/common-changelog.svg)](https://common-changelog.org)
[![license](https://img.shields.io/badge/license-Polyform_Non_Commercial-26bc71?style=flat-square)](LICENSE)

An extra minimal parent class for [web components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components).

This extends the native `HTMLElement`, adding some methods to help with events.

[See a live demonstration](https://substrate-system.github.io/web-component/)

- [install](#install)
- [tl;dr](#tldr)
- [Example](#example)
* [Create a component](#create-a-component)
* [Add the component to the DOM](#add-the-component-to-the-dom)
* [Listen for events](#listen-for-events)
* [Emit a namespaced event from the instance](#emit-a-namespaced-event-from-the-instance)
* [Emit a plain string (not namespaced) event](#emit-a-plain-string-not-namespaced-event)
- [API](#api)
* [Modules](#modules)
* [Common JS](#common-js)
- [methods](#methods)
* [`emit(name:string, opts:{ bubbles?, cancelable?, detail? }):boolean`](#emitnamestring-opts-bubbles-cancelable-detail-boolean)
* [`dispatch (type, opts)`](#dispatch-type-opts)
* [`event (name:string):string`](#event-namestringstring)
* [`qs`](#qs)
* [`qsa`](#qsa)
- [Misc](#misc)
* [`isRegistered`](#isregistered)
- [Develop](#develop)
- [Test](#test)
- [See also](#see-also)

## install

```bash
npm i -S @substrate-system/web-component
```

## tl;dr

* [use `.emit` to emit a namepsaced event](#emit-a-namespaced-event-from-the-instance)
* [use `.dispatch` to emit a non-namespaced event](#emit-a-plain-string-not-namespaced-event)
* [use `.event(name)` to get the namespaced event type](#listen-for-events)
* [extend the factory function's return value to create a web component](#create-a-component)

## Example

### Create a component
Use the factory function to create a new web component.

```js
import { WebComponent } from '@substrate-system/web-component'

class AnotherElement extends WebComponent.create('another-element') {
constructor () {
super()
}

connectedCallback () {
this.innerHTML = `


hello again
`
}
}

customElements.define(AnotherElement.NAME, AnotherElement)
```

The new component will have a property `NAME` on the class that is equal to [the name you passed in](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define#valid_custom_element_names). The component name should be [kebab case](https://developer.mozilla.org/en-US/docs/Glossary/Kebab_case).

### Add the component to the DOM
```js
document.body.innerHTML += ''
```

### Listen for events

Use a helper method, `WebComponent.event(name:string)`, to get a
namespaced event name.

```js
// find the instance
const el = document.querySelector('my-element')

// listen for namespaced events
el?.addEventListener(MyElement.event('hello'), ev => {
console.log(ev.detail) // => 'some data'
})

// listen for non-namespaced events
el?.addEventListener('hello', ev => {
console.log(ev.detail) // => 'some data again'
})
```

### Emit a namespaced event from the instance

```js
// find the instance
const el = document.querySelector('my-element')

// dispatch an event
el?.emit('hello', { detail: 'some data' }) // => `my-element:hello`
```

### Emit a plain string (not namespaced) event
Don't namespace the event name, just emit the literal string.

```js
const el = document.querySelector('my-element')

// dispatch an event as plain string, not namespaced
el?.dispatch('hello', { detail: 'some data again' }) // => `hello`
```

## API

### Modules

This exposes ESM and common JS via [package.json `exports` field](https://nodejs.org/api/packages.html#exports).

```js
const { WebComponent } = import '@substrate-system/web-component'
```

### Common JS
```js
const { WebCompponent } = require('@substrate-system/web-component')
```

## methods

### `emit(name:string, opts:{ bubbles?, cancelable?, detail? }):boolean`

This will emit a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events), namespaced according to a convention.

The return value is [the same as the native `.dispatchEvent` method](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent),

> returns `true` if either event's `cancelable` attribute value is false or its `preventDefault()` method was not invoked, and `false` otherwise.

Because the event is namespaced, we can use event bubbling while minimizing event name collisions.

The naming convention is to take the `NAME` property of the class, and append a string `:event-name`.

So `emit('test')` dispatches an event like `my-element:test`.

```js
class MyElement {
NAME = 'my-element' // <-- for event namespace
// ...
}

// ... then use the element in markup ...

const el = document.querySelector('my-element')

// 'my-element:test' event
el.addEventListener(MyElement.event('test'), ev => {
console.log(ev.detail) // => 'some data'
})

// ... in the future ...

el.emit('test', 'some data') // dispatch `my-element:test` event
```

See also, [Custom events in Web Components](https://gomakethings.com/custom-events-in-web-components/)

-------------------------------------------------------------------

### `dispatch (type, opts)`
Create and emit an event, no namespacing. The return value is the same as the
native `.dispatchEvent` method,

> returns `true` if either event's `cancelable` attribute value is false or its `preventDefault()` method was not invoked, and `false` otherwise.

That is, it returns true if it was not `preventDetault`ed.

```ts
dispatch (type:string, opts:Partial<{
bubbles,
cancelable,
detail
}>):boolean
```

#### `dispatch` example
```js
const el = document.querySelector('my-element')
el.dispatch('change') // => 'change' event
```

-------------------------------------------------------------------

### `event (name:string):string`
Return the namespaced event name.

#### `event` example

```js
MyElement.event('change') // => 'my-element:change'
```

### `qs`
A convenient shortcut to `element.querySelector`.

```ts
qs (selector:string):HTMLElement|null
```

### `qsa`
Shortcut to `element.querySelectorAll`

```ts
qsa (selector:string):ReturnType
```

#### example
```js
const myElement = document.querySelector('my-element')
debug('the namespaced event...', MyElement.event('aaa'))

// query inside the element
const buttons = myElement?.qsa('button')
```

---------------------------------------------------------------------

## Misc

### `isRegistered`
Check if an element name has been used already.

```ts
function isRegistered (elName:string):boolean
```

#### example
```js
import { isRegistered } from '@substrate-system/web-component'

if (!isRegistered('example-component')) {
customElements.define('example-component', ExampleComponent)
}
```

---------------------------------------------------------------------

## Develop
Start a localhost server:

```bash
npm start
```

------------------------------------------------------------------------

## Test

```bash
npm test
```

-------------------------------------------------

## See also

* [Custom events in Web Components](https://gomakethings.com/custom-events-in-web-components/)
* [Web Component lifecycle methods](https://gomakethings.com/the-web-component-lifecycle-methods/)
* [How to detect when attributes change on a Web Component](https://gomakethings.com/how-to-detect-when-attributes-change-on-a-web-component/)
* [Handling asychronous rendering in Web Components](https://gomakethings.com/handling-asychronous-rendering-in-web-components/)