-
Notifications
You must be signed in to change notification settings - Fork 1
VI. Mount‐based web components
Let's move on now to what has become the sine qua non example for web components. The counter. Now we have a rudimentary UI, so we can see how xtal-element approaches this. As always we show the optional TypeScript version. The JS version isn't that different, just remove a little sugar (or toxic chemical waste, depending on your perspective) here and there:
import {MntCfg, Mount, MountActions, MountProps} from 'trans-render/Mount.js';
import {localize} from 'trans-render/funions/Localizer.js';
import { ITransformer, UnitOfWork } from 'trans-render/types.js';
export interface DTRCounterProps {
count: number;
}
export interface DTRCounterMethods {
localize(model: any, transformer: ITransformer<any, any>, uow: UnitOfWork<any, any>, matchingElement: Element): string | Partial<HTMLDataElement> | Partial<HTMLTimeElement> | undefined;
}
const html = String.raw;
export class DTRCounter extends Mount{
localize = localize
static override config: MntCfg<DTRCounterProps & MountProps, DTRCounterMethods & MountActions> = {
name: 'dtr-counter',
shadowRootInit:{
mode: 'open'
},
mainTemplate: html `
<button part=down data-d=-1>-</button>
<data part=count aria-live=polite></data>
<button part=up data-d=1>+</button>`,
propDefaults:{
count: 30,
},
propInfo: {
...super.mntCfgMxn.propInfo,
},
actions:{
...super.mntCfgMxn.actions
},
xform: {
'% count': 'localize',
button: {
m: {
on: 'click',
inc: 'count',
byAmt: '.dataset.d',
},
}
},
styles: [
html `
<style>
:host{
display: block;
}
* {
font-size: 200%;
}
span {
width: 4rem;
display: inline-block;
text-align: center;
}
button {
width: 4rem;
height: 4rem;
border: none;
border-radius: 10px;
background-color: seagreen;
color: white;
}
</style>
`
]
}
}
await DTRCounter.bootUp();
customElements.define(DTRCounter.config.name!, DTRCounter);
- We have kept the binding syntax separate from the markup syntax, similar to CSS. This is based on mount-observing transform syntax. This means migrating to something else should be easier, as the library dependencies aren't all tangled up with the actual presentation structure. Okay, maybe not such a big deal, but just saying.
- What I would like to impress upon you is there isn't any code (if we squint our eyes a bit)! It's mostly all JSON serializable, making it truly declarative.
- So using this technique, we can envision a large number of web components that can already be made declarative, even without HTML Modules -- using JSON modules, where the JSON module contains a clob or two of HTML, and a clob of CSS.
Now before you run away, justifiably repelled by the notion of editing JSON, I hear you. You and I are cut from the same cloth.
A light-touch "compiler" (or "transpiler"?) is provided by the may-it-be package. So we can edit *.mts files, and benefit from all the typing goodness TypeScript provides, or *.mjs files, and the may-it-be transpiler can output to a file for distribution, that formats the source file into the tightly constrained format that JSON requires. (The may-it-be transpiler also supports another output option -- HTML with declarative ShadowDOM, discussed later.)