UNPKG

web-component-wrapper

Version:

Generic web-component base class and framework specific wrapper.

202 lines (157 loc) 7.75 kB
<!-- !/usr/bin/env markdown -*- coding: utf-8 -*- region header Copyright Torben Sickert (info["~at~"]torben.website) 16.12.2012 License ------- This library written by Torben Sickert stands under a creative commons naming 3.0 unported license. See https://creativecommons.org/licenses/by/3.0/deed.de endregion --> Project status -------------- [![npm](https://img.shields.io/npm/v/web-component-wrapper?color=%23d55e5d&label=npm%20package%20version&logoColor=%23d55e5d&style=for-the-badge)](https://www.npmjs.com/package/web-component-wrapper) [![npm downloads](https://img.shields.io/npm/dy/web-component-wrapper.svg?style=for-the-badge)](https://www.npmjs.com/package/web-component-wrapper) [![build](https://img.shields.io/github/actions/workflow/status/thaibault/web-component-wrapper/build.yaml?style=for-the-badge)](https://github.com/thaibault/web-component-wrapper/actions/workflows/build.yaml) [![build push package](https://img.shields.io/github/actions/workflow/status/thaibault/web-component-wrapper/build-package-and-push.yaml?label=build%20push%20package&style=for-the-badge)](https://github.com/thaibault/web-component-wrapper/actions/workflows/build-package-and-push.yaml) [![check types](https://img.shields.io/github/actions/workflow/status/thaibault/web-component-wrapper/check-types.yaml?label=check%20types&style=for-the-badge)](https://github.com/thaibault/web-component-wrapper/actions/workflows/check-types.yaml) [![lint](https://img.shields.io/github/actions/workflow/status/thaibault/web-component-wrapper/lint.yaml?label=lint&style=for-the-badge)](https://github.com/thaibault/web-component-wrapper/actions/workflows/lint.yaml) [![test](https://img.shields.io/github/actions/workflow/status/thaibault/web-component-wrapper/test-coverage-report.yaml?label=test&style=for-the-badge)](https://github.com/thaibault/web-component-wrapper/actions/workflows/test-coverage-report.yaml) [![code coverage](https://img.shields.io/coverallsCoverage/github/thaibault/web-component-wrapper?label=code%20coverage&style=for-the-badge)](https://coveralls.io/github/thaibault/web-component-wrapper) [![deploy web documentation](https://img.shields.io/github/actions/workflow/status/thaibault/web-component-wrapper/deploy-web-documentation.yaml?label=deploy%20web%20documentation&style=for-the-badge)](https://github.com/thaibault/web-component-wrapper/actions/workflows/deploy-web-documentation.yaml) [![web documentation](https://img.shields.io/website-up-down-green-red/https/torben.website/web-component-wrapper.svg?label=web-documentation&style=for-the-badge)](https://torben.website/web-component-wrapper) Use case -------- Encapsulate your components as web-components. <div class="wd-table-of-contents"> <h2 id="content">Content<!--deDE:Inhalt--></h2> <!--wd-table-of-contents--> </div> <!--|deDE:Installation--> Installation ------------ You can install via package manager, simply download the compiled version as zip file here and inject or request via cdn in HTML: <!--deDE: Sie können das Paket über den Paketmanager installieren oder einfach die kompilierte Version als ZIP-Datei hier herunterladen und in HTML einbinden oder über ein CDN abrufen: --> ```bash npm install web-component-wrapper ``` ```TypeScript import {func, object} from 'clientnode/property-types' import {property} from 'web-component-wrapper/decorator' import {Web} from 'web-component-wrapper/Web' export class MyWebComponent< TElement = HTMLElement, ExternalProperties extends Mapping<unknown> = Mapping<unknown>, InternalProperties extends Mapping<unknown> = Mapping<unknown> > extends Web<TElement, ExternalProperties, InternalProperties> { static content = ` <div class="wrapper" on-click="this.rootInstance.onClick(event)"> <slot>Please provide a template to transclude.</slot> </div> ` @property({type: object}) options = {} as Options @property({type: func}) onClick: (event: MouseEvent) => Promise<void> = NOOP /** * Defines dynamic getter and setter interface and resolves a configuration * object. Initializes the map implementation. */ constructor() { super() /* Babel property declaration transformation overwrites defined properties at the end of an implicit constructor. So we have to redefine them as long as we want to declare expected component interface properties to enable static type checks. */ this.defineGetterAndSetterInterface() } /** * Triggered when ever a given attribute has changed and triggers to update * configured dom content. * @param name - Attribute name which was updates. * @param newValue - New updated value. * @returns Returns when attribute has been updated. */ async onUpdateAttribute(name: string, newValue: string): Promise<void> { await super.onUpdateAttribute(name, newValue) // ... } /** * Updates controlled dom elements. * @param reason - Why an update has been triggered. * @param resolveRendering - Indicates whether rendering should be resolved * finally. Should be set to "false" via super calls in inherited render * methods which do further dom manipulations afterward and resolve the * rendering process by their own. * @returns A promise resolving when rendering has finished. A promise may * be needed for classes inheriting from this class. */ async render(reason = 'unknown', resolveRendering = true): Promise<void> { await super.render(reason, false) await this.waitForNestedComponentRendering() // ... await this.resolveRenderingPromiseIfSet(reason, resolveRendering) } // ... } customElements.define('my-web-component', MyWebComponent) ``` <!--|deDE:Beispiele--> Examples -------- <!--|deDE:Lade via CDN--> ### Load via CDN <!--showExample:hidden--> ```HTML <script src="https://unpkg.com/web-component-wrapper@latest/dist/bundle/index.js" ></script> ``` <!--|deDE:Einfaches Web-Component Beispiel--> ### Simple Web-Component <!--showExample:JavaScript--> ```JavaScript class MyGreeting extends webComponentWrapper.Web { static doRender = true static evaluateSlots = true static determineRootBinding = false static content = '<div>Hello ${rootInstance.greetingName}</div>' } // Alternative to the decorator syntax: webComponentWrapper.property()({self: MyGreeting}, 'greetingName') customElements.define('my-greeting', MyGreeting) ``` <!--showExample--> ```HTML <my-greeting greeting-name="World"></my-greeting> ``` <!--|deDE:Einfaches React-Web-Component Beispiel--> ### Simple React-Web-Component ```JavaScript class MyReactGreeting extends webComponentWrapper.ReactWeb { static doRender = true static evaluateSlots = true // Content has a react component to wrap. static content = ({name}) => <div>Hello {name}</div> } // Alternative to the decorator syntax: webComponentWrapper.property()({self: MyReactGreeting}, 'name') customElements.define('my-react-greeting', MyReactGreeting) ``` ### Data-Flow Data can flow into a component via - External property set `instance.value = 'value'` - Trigger Events `instance.triggerEvent('click')` Data can be communicated back via: - Properties `log.info(instance.value)` - Observable events `instance.addEventListener('click', (event) => console.log(event.detail.value))` #### Configuring Data-Flow A Web-Component-Wrapper component forwards (transformed) given properties into a wrapped React component via `props` and reads data via provided callbacks as part of `props` or as part of reacts `ref` object.