From 528a865d79b8bc71d375991e2f3f6462776b9946 Mon Sep 17 00:00:00 2001 From: Jan Andrle Date: Wed, 5 Jun 2024 16:20:12 +0200 Subject: [PATCH] :abc: Web Components (WIP) --- docs/p06-customElement.html | 60 +++++++++++++++++-- .../customElement/customElementWithDDE.js | 17 ++++++ .../components/examples/customElement/dde.js | 33 ++++++++++ .../examples/customElement/native-basic.js | 6 +- docs_src/p06-customElement.html.js | 12 +++- 5 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 docs_src/components/examples/customElement/customElementWithDDE.js create mode 100644 docs_src/components/examples/customElement/dde.js diff --git a/docs/p06-customElement.html b/docs/p06-customElement.html index 9685846..e7b295d 100644 --- a/docs/p06-customElement.html +++ b/docs/p06-customElement.html @@ -1,4 +1,4 @@ -`deka-dom-el` — Web Components

`deka-dom-el` — Web Components

Using custom elements in combinantion with DDE

Using web components in combinantion with DDE

The DDE library allows for use within Web Components for dom-tree generation. However, in order to be able to use signals (possibly mapping to registered observedAttributes) and additional functionality is (unfortunately) required to use helpers provided by the library.

// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js +`deka-dom-el` — Web Components

`deka-dom-el` — Web Components

Using custom elements in combinantion with DDE

Using web components in combinantion with DDE

The DDE library allows for use within Web Components for dom-tree generation. However, in order to be able to use signals (possibly mapping to registered observedAttributes) and additional functionality is (unfortunately) required to use helpers provided by the library.

// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js import { customElementRender, customElementWithDDE, @@ -10,8 +10,8 @@ S.observedAttributes; // “internal” utils import { lifecyclesToEvents } from "deka-dom-el"; -

# Custom Elements Introduction

To start with, let’s see how to use native Custom Elements. As starting point please read Using Custom Elements on MDN. To sum up and for mnemonic see following code overview:

export class CustomHTMLElement extends HTMLElement{ - static tagName= "custom-element"; // just suggestion, we can use `el(CustomHTMLElement.tagName)` +

# Custom Elements Introduction

To start with, let’s see how to use native Custom Elements. As starting point please read Using Custom Elements on MDN. To sum up and for mnemonic see following code overview:

export class HTMLCustomElement extends HTMLElement{ + static tagName= "custom-element"; // just suggestion, we can use `el(HTMLCustomElement.tagName)` static observedAttributes= [ "custom-attribute" ]; constructor(){ super(); @@ -30,5 +30,55 @@ import { lifecyclesToEvents } from "deka-dom-el"; get customAttribute(){ return this.getAttribute("custom-attribute"); } set customAttribute(value){ this.setAttribute("custom-attribute", value); } } -customElements.define(CustomHTMLElement.tagName, CustomHTMLElement); -

For more advanced use of Custom Elements, the summary Handy Custom Elements' Patterns may be useful. Especially pay attention to linking HTML attributes and defining setters/getters, this is very helpful to use in combination with the library (el(CustomHTMLElement.tagName, { customAttribute: "new-value" });).

# Mnemonic

  • customElementRender(<custom-element>, <render-function>[, <properties>]) — use function to render DOM structure for given <custom-element>
  • customElementWithDDE(<custom-element>) — register <custom-element> to DDE library, see also `lifecyclesToEvents`, can be also used as decorator
  • observedAttributes(<custom-element>) — returns record of observed attributes (keys uses camelCase)
  • S.observedAttributes(<custom-element>) — returns record of observed attributes (keys uses camelCase and values are signals)
  • lifecyclesToEvents(<class-declaration>) — convert lifecycle methods to events, can be also used as decorator
\ No newline at end of file +customElements.define(HTMLCustomElement.tagName, HTMLCustomElement); +

For more advanced use of Custom Elements, the summary Handy Custom Elements' Patterns may be useful. Especially pay attention to linking HTML attributes and defining setters/getters, this is very helpful to use in combination with the library (el(HTMLCustomElement.tagName, { customAttribute: "new-value" });).

Also see the Life Cycle Events sections, very similarly we would like to use DDE events. To do it, the library provides function customElementWithDDE

import { customElementWithDDE, el, on } from "./esm-with-signals.js"; +export class HTMLCustomElement extends HTMLElement{ + static tagName= "custom-element"; + connectedCallback(){ + this.append( + el("p", "Hello from custom element!") + ); + } +} +customElementWithDDE(HTMLCustomElement); +customElements.define(HTMLCustomElement.tagName, HTMLCustomElement); + +const instance= el(HTMLCustomElement.tagName); +on.connected(e=> console.log("Element connected to the DOM:", e))(instance); +document.body.append( + instance, +); +

Custom Elements with DDE

import { + customElementRender, + customElementWithDDE, +} from "./esm-with-signals.js"; +export class HTMLCustomElement extends HTMLElement{ + static tagName= "custom-element"; + static observedAttributes= [ "attr" ]; + connectedCallback(){ + customElementRender( + this, + this.attachShadow({ mode: "open" }), + ddeComponent + ); + } + set attr(value){ this.setAttribute("attr", value); } + get attr(){ return this.getAttribute("attr"); } +} + +import { el, on, scope } from "./esm-with-signals.js"; +function ddeComponent({ attr }){ + scope.host( + on.connected(e=> console.log(this.outerHTML)), + ); + return el().append( + el("p", `Hello from Custom Element with attribute '${attr}'`) + ) +} +customElementWithDDE(HTMLCustomElement); +customElements.define(HTMLCustomElement.tagName, HTMLCustomElement); + +document.body.append( + el(HTMLCustomElement.tagName, { attr: "Attribute" }) +); +

# Mnemonic

  • customElementRender(<custom-element>, <render-function>[, <properties>]) — use function to render DOM structure for given <custom-element>
  • customElementWithDDE(<custom-element>) — register <custom-element> to DDE library, see also `lifecyclesToEvents`, can be also used as decorator
  • observedAttributes(<custom-element>) — returns record of observed attributes (keys uses camelCase)
  • S.observedAttributes(<custom-element>) — returns record of observed attributes (keys uses camelCase and values are signals)
  • lifecyclesToEvents(<class-declaration>) — convert lifecycle methods to events, can be also used as decorator
\ No newline at end of file diff --git a/docs_src/components/examples/customElement/customElementWithDDE.js b/docs_src/components/examples/customElement/customElementWithDDE.js new file mode 100644 index 0000000..9ccdade --- /dev/null +++ b/docs_src/components/examples/customElement/customElementWithDDE.js @@ -0,0 +1,17 @@ +import { customElementWithDDE, el, on } from "deka-dom-el"; +export class HTMLCustomElement extends HTMLElement{ + static tagName= "custom-element"; + connectedCallback(){ + this.append( + el("p", "Hello from custom element!") + ); + } +} +customElementWithDDE(HTMLCustomElement); +customElements.define(HTMLCustomElement.tagName, HTMLCustomElement); + +const instance= el(HTMLCustomElement.tagName); +on.connected(e=> console.log("Element connected to the DOM:", e))(instance); +document.body.append( + instance, +); diff --git a/docs_src/components/examples/customElement/dde.js b/docs_src/components/examples/customElement/dde.js new file mode 100644 index 0000000..db38432 --- /dev/null +++ b/docs_src/components/examples/customElement/dde.js @@ -0,0 +1,33 @@ +import { + customElementRender, + customElementWithDDE, +} from "deka-dom-el"; +export class HTMLCustomElement extends HTMLElement{ + static tagName= "custom-element"; + static observedAttributes= [ "attr" ]; + connectedCallback(){ + customElementRender( + this, + this.attachShadow({ mode: "open" }), + ddeComponent + ); + } + set attr(value){ this.setAttribute("attr", value); } + get attr(){ return this.getAttribute("attr"); } +} + +import { el, on, scope } from "deka-dom-el"; +function ddeComponent({ attr }){ + scope.host( + on.connected(e=> console.log(e.target.outerHTML)), + ); + return el().append( + el("p", `Hello from Custom Element with attribute '${attr}'`) + ) +} +customElementWithDDE(HTMLCustomElement); +customElements.define(HTMLCustomElement.tagName, HTMLCustomElement); + +document.body.append( + el(HTMLCustomElement.tagName, { attr: "Attribute" }) +); diff --git a/docs_src/components/examples/customElement/native-basic.js b/docs_src/components/examples/customElement/native-basic.js index d54fc3e..3a7ff42 100644 --- a/docs_src/components/examples/customElement/native-basic.js +++ b/docs_src/components/examples/customElement/native-basic.js @@ -1,5 +1,5 @@ -export class CustomHTMLElement extends HTMLElement{ - static tagName= "custom-element"; // just suggestion, we can use `el(CustomHTMLElement.tagName)` +export class HTMLCustomElement extends HTMLElement{ + static tagName= "custom-element"; // just suggestion, we can use `el(HTMLCustomElement.tagName)` static observedAttributes= [ "custom-attribute" ]; constructor(){ super(); @@ -18,4 +18,4 @@ export class CustomHTMLElement extends HTMLElement{ get customAttribute(){ return this.getAttribute("custom-attribute"); } set customAttribute(value){ this.setAttribute("custom-attribute", value); } } -customElements.define(CustomHTMLElement.tagName, CustomHTMLElement); +customElements.define(HTMLCustomElement.tagName, HTMLCustomElement); diff --git a/docs_src/p06-customElement.html.js b/docs_src/p06-customElement.html.js index 0dbdbfd..1913473 100644 --- a/docs_src/p06-customElement.html.js +++ b/docs_src/p06-customElement.html.js @@ -58,8 +58,18 @@ export function page({ pkg, info }){ For more advanced use of Custom Elements, the summary ${el("a", references.custom_elements_tips) .append( el("strong", t`Handy Custom Elements' Patterns`) )} may be useful. Especially pay attention to linking HTML attributes and defining setters/getters, this is very helpful to use in combination with - the library (${el("code", "el(CustomHTMLElement.tagName, { customAttribute: \"new-value\" });")}). + the library (${el("code", "el(HTMLCustomElement.tagName, { customAttribute: \"new-value\" });")}). `), + el("p").append(...T` + Also see the Life Cycle Events sections, very similarly we would like to use + ${el("a", { textContent: t`DDE events`, href: "./p03-events.html", title: t`See events part of the library documentation` })}. + To do it, the library provides function ${el("code", "customElementWithDDE")}… + `), + el(example, { src: fileURL("./components/examples/customElement/customElementWithDDE.js"), page_id }), + + el("h3", t`Custom Elements with DDE`), + el(example, { src: fileURL("./components/examples/customElement/dde.js"), page_id }), + el(mnemonic) );