ex-greeting

This example demonstrates how to leverage on some builders and decorators to create a Custom Element which displays a greeting message.

The example is available on codepen.io!

Initiate the Custom Element class

The Custom Element ex-greeting is a regular ES6 class which extends HTMLElement :

export class ExGreeting extends HTMLElement {}

Register the Custom Element

To register ex-greeting, the decorator of @ElementBuilder is used:

import { ElementBuilder } from "@tmorin/ceb-elements-core"

@ElementBuilder.get().decorate()
export class ExGreeting extends HTMLElement {}

Initialize the Shadow DOM

The Shadow DOM of ex-greeting is initialized with the decorator of @ContentBuilder :

import { ElementBuilder } from "@tmorin/ceb-elements-core"
import { ContentBuilder } from "@tmorin/ceb-elements-builders"

@ElementBuilder.get().decorate()
@ContentBuilder.get(`<p>Hello, <span id="name"></span>!</p>`)
  .shadow()
  .decorate()
export class ExGreeting extends HTMLElement {}

Capture the name

The target of the greeting is captured with the field name using the decorator of FieldBuilder :

import { ElementBuilder } from "@tmorin/ceb-elements-core"
import { ContentBuilder, FieldBuilder } from "@tmorin/ceb-elements-builders"

@ElementBuilder.get().decorate()
@ContentBuilder.get(`<p>Hello, <span id="name"></span>!</p>`)
  .shadow()
  .decorate()
export class ExGreeting extends HTMLElement {
  @FieldBuilder.get().decorate()
  name: string = "World"
}

Update the Shadow DOM with the captured name

Each time the field name mutates, the element selected by span#name has to be updated with the new value. There are two ways to handle it with the built-in <ceb/> builders : the craft style and the propagation way.

The craft style

The decorator of ReferenceBuilder retrieves the reference of the element span#name.

import { ElementBuilder } from "@tmorin/ceb-elements-core"
import {
  ContentBuilder,
  FieldBuilder,
  ReferenceBuilder,
} from "@tmorin/ceb-elements-builders"

@ElementBuilder.get().decorate()
@ContentBuilder.get(`<p>Hello, <span id="name"></span>!</p>`)
  .shadow()
  .decorate()
export class ExGreeting extends HTMLElement {
  @FieldBuilder.get().decorate()
  name: string = "World"

  @ReferenceBuilder.get().shadow().selector("span#name").decorate()
  span?: HTMLSpanElement
}

Finally, the decorator of FieldBuilder handles the mutation of the field name.

import { FieldListenerData } from "@tmorin/ceb-elements-builders"
import { ElementBuilder } from "@tmorin/ceb-elements-core"
import {
  ContentBuilder,
  FieldBuilder,
  ReferenceBuilder,
} from "@tmorin/ceb-elements-builders"

@ElementBuilder.get().decorate()
@ContentBuilder.get(`<p>Hello, <span id="name"></span>!</p>`)
  .shadow()
  .decorate()
export class ExGreeting extends HTMLElement {
  @FieldBuilder.get().decorate()
  name: string = "World"

  @ReferenceBuilder.get().shadow().selector("span#name").decorate()
  span?: HTMLSpanElement

  @FieldBuilder.get().decorate()
  private onName(data: FieldListenerData<string>) {
    if (this.span) {
      this.span.textContent = data.newVal
    }
  }
}

The propagation way

Alternatively, the decorator of AttributePropagationBuilder can be used to automatically binds the mutation of the field name to the property textContent of the selected element span#name :

import { ElementBuilder } from "@tmorin/ceb-elements-core"
import { ContentBuilder, FieldBuilder, FieldListenerData, ReferenceBuilder } from "@tmorin/ceb-elements-builders"

@ElementBuilder.get<ExGreeting>().decorate()
@ContentBuilder.get(`<p>Hello, <span id="name"></span>!</p>`).shadow().decorate()
export class ExGreeting extends HTMLElement {
  @ReferenceBuilder.get().shadow().selector("span#name").decorate()
  span?: HTMLSpanElement

  @FieldBuilder.get().decorate()
  name = "World"

  @FieldBuilder.get().decorate()
  private onName(data: FieldListenerData<string>) {
    if (this.span) {
      this.span.textContent = data.newVal
    }
  }
}